为什么应用程序在协程尝试进入 Dispatchers.Main 时终止?
Why application terminates when coroutine tries to enter Dispatchers.Main?
我正在尝试添加协程,首先将 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 中启用了 "show only selected application"?或者其他类型的过滤器?
因为当我 运行 你的代码时,我得到了这个非常有用的崩溃:
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.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"
一些其他注意事项:
- 您不想在点击侦听器中使用
findViewById
。您应该执行该任务一次 - 可能在 onCreate
- 然后将其保存到 class 级别 属性.
- 您真的不需要在该点击侦听器中使用
launch
。
- 如果您要使用协程,那么 class 应该只实现
CoroutineScope
。这意味着您不必在每次要使用 launch
或 async
. 时都创建新上下文或使用 GlobalScope
在你的混淆文件中添加这一行
-保持 class kotlinx.coroutines.android.* {*;}
这与我在协程范围内使用 Retrofit 从 Internet 获取一些数据时遇到的错误相同。
修复非常简单,就是在我的测试物理设备中打开互联网。
我正在尝试添加协程,首先将 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 中启用了 "show only selected application"?或者其他类型的过滤器?
因为当我 运行 你的代码时,我得到了这个非常有用的崩溃:
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.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"
一些其他注意事项:
- 您不想在点击侦听器中使用
findViewById
。您应该执行该任务一次 - 可能在onCreate
- 然后将其保存到 class 级别 属性. - 您真的不需要在该点击侦听器中使用
launch
。 - 如果您要使用协程,那么 class 应该只实现
CoroutineScope
。这意味着您不必在每次要使用launch
或async
. 时都创建新上下文或使用
GlobalScope
在你的混淆文件中添加这一行
-保持 class kotlinx.coroutines.android.* {*;}
这与我在协程范围内使用 Retrofit 从 Internet 获取一些数据时遇到的错误相同。
修复非常简单,就是在我的测试物理设备中打开互联网。