android - 为什么当协程试图进入 Dispatchers.Main 时应用程序终止?

标签 android kotlin kotlin-coroutines

我正在尝试添加协程,首先将 progressBar 设置为可见,然后向服务器请求数据,当它获取数据时,将 progressBar 设置为不可见。我读过要与 UI 交互,我的协程需要在 Dispatcher.Main 中运行,但是当我尝试设置 launch(Dispatcher.Main) 时,整个 应用程序终止没有错误

我从以下教程开始:https://www.kotlindevelopment.com/deep-dive-coroutines/ .我更改了那里显示的代码的一部分:

launch(UI) {
  progressBar.visibility = View.VISIBLE
  try {
    val userString = fetchUserString("1").await()
    val user = deserializeUser(userString).await()
    showUserData(user)
  } catch (ex: Exception) {
    log(ex)
  } finally {
    progressBar.visibility = View.GONE
  }
}

到:

GlobalScope.launch(Dispatchers.Main) {
                progressBarMarkers.visibility = View.VISIBLE
                try {
                    val repository = MarkerRepository()
                    points = repository.getAllDataAsync().await()
                    }
               } catch (ex: Exception) {
                    Log.d("EXCEPTION", ex.toString())
               } finally {
                    progressBarMarkers.visibility = View.INVISIBLE
                }
            }

但是没有用。我开始搜索可能是什么问题,我发现当我的协程如下所示时,应用程序在到达 withContext(Dispatchers.Main)

时终止
GlobalScope.launch{
        val button = findViewById<ProgressBar>(R.id.progressBarMarkers)
        withContext(Dispatchers.Main){
                button.visibility = View.VISIBLE
        }
}

我对 Kotlin 和协同程序还是很陌生,所以也许这只是一些基本的错误,但我找不到应用程序终止的原因,更重要的是没有错误终止

整个协程在:

class MapsActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var mMap: GoogleMap
    private val REQUEST_PERMISSION_CODE: Int = 123
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_maps)
        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)

        ShowPlacesButton.setOnClickListener {
            launch{
                val button = findViewById<ProgressBar>(R.id.progressBarMarkers)
                withContext(Dispatchers.Main + Job()){
                    button.visibility = View.VISIBLE
                }
        }
    }
}

和我的 gradle 文件的一部分:

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.google.android.gms:play-services-maps:16.1.0'
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"
    implementation 'com.google.dagger:dagger:2.13'
    kapt 'com.google.dagger:dagger-compiler:2.13'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
}

为什么应用在到达 Dispatcher.Main 时终止?

最佳答案

您是否在 logcat 中启用了“仅显示选定的应用程序”?或者其他类型的过滤器?

因为当我运行你的代码时,我遇到了这个非常有用的崩溃:

E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
    Process: com.idunnno.test, PID: 27501
    java.lang.IllegalStateException: Module with the Main dispatcher is missing. Add dependency providing the Main dispatcher, e.g. 'kotlinx-coroutines-android'
        at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.missing(MainDispatchers.kt:73)
        at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.isDispatchNeeded(MainDispatchers.kt:54)
        at kotlinx.coroutines.DispatchedKt.resumeCancellable(Dispatched.kt:373)
        at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:25)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:152)
        at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
        at com.idunnno.daggertest.MainActivity$onCreate$1$1.invokeSuspend(MainActivity.kt:27)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
        at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)

基本修复是将此行添加到您的 Gradle 依赖项中:

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"

一些其他注意事项:

  1. 您不想在点击监听器中使用 findViewById。您应该执行该任务一次 - 可能在 onCreate 中 - 然后将其保存到类级属性中。
  2. 您真的不需要在该点击监听器中使用 launch
  3. 如果您打算使用协程,那么该类应该只实现CoroutineScope。这意味着您不必在每次要使用 launchasync 时都创建新上下文或使用 GlobalScope

关于android - 为什么当协程试图进入 Dispatchers.Main 时应用程序终止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55659029/

相关文章:

android - BottomNavigationView.setupWithNavController 不工作

android - 类型不匹配 : inferred type is HomeViewModel! 但 ViewModel!预计

java - 为什么我的协程异步只能在 runBlocking 内工作?

kotlin - 协程 : runBlocking vs coroutineScope

java - 尝试从特定列检索值时,获取 java.lang.String 无法转换为 JSONObject

java - Recyclerview 适配器不刷新

android - 将背景放在线性布局上,几乎占据屏幕的 3/4

java - Jackson 的 @JsonAppend 具有默认值

android - Kotlin 协程 - 线程切换

android - Flutter:在一组小部件中组合Draggable和GestureDetector