【发布时间】:2019-09-25 13:20:36
【问题描述】:
看完Sean's explanation on Android (Google I/O'19)我也试过了:
init{
viewModelScope.launch {
Timber.i("coroutine awake")
while (true){
delay(2_000)
Timber.i("another round trip")
}
}
}
不幸的是 onCleared 它在 Activity 被终止时被调用,但在它被置于后台时不会被调用(“当我们离开 Activity 时......”,背景是“离开”恕我直言^^)。
我得到以下输出:
> ---- Activity in Foreground
> 12:41:10.195 TEST: coroutine awake
> 12:41:12.215 TEST: another round trip
> 12:41:14.231 TEST: another round trip
> 12:41:16.245 TEST: another round trip
> 12:41:18.259 TEST: another round trip
> 12:41:20.270 TEST: another round trip
> ----- Activity in Background (on onCleared not fired)
> 12:41:22.283 TEST: another round trip
> 12:41:24.303 TEST: another round trip
> 12:41:26.320 TEST: another round trip
> 12:41:28.353 TEST: another round trip
> 12:41:30.361 TEST: another round trip
> ----- Activity in Foreground
> 12:41:30.369 TEST: coroutine awake
我该如何解决这个问题?
1 - 将代码从init 移动到suspend fun start() 由lifecycleScope.launchWhenStarted 内的活动调用?
我得到相同的结果。我以为lifecycleScope 在进入后台时会取消它的子协程,但我用这种方法得到了相同的 Timber 输出。
2 - 将我的 ViewModel 代码更改为:
private lateinit var job: Job
suspend fun startEmitting() {
job = viewModelScope.launch {
Timber.i("coroutine awake")
while (true){
delay(2_000)
Timber.i("another round trip")
}
}
}
fun cancelJob(){
if(job.isActive){
job.cancel()
}
}
而且,在我的活动中:
override fun onResume() {
super.onResume()
lifecycleScope.launch {
viewModel.startEmitting()
}
}
override fun onPause() {
super.onPause()
viewModel.cancelJob()
}
它可以工作,但viewModelScope 的目的不是为我管理CoroutineScope 吗?我讨厌这种 cancelJob 逻辑。
解决这个问题的最佳方法是什么?
【问题讨论】:
-
ViewModel 不知道 Activity 的生命周期,它只会对被销毁的 Activity 做出反应。您可以将您的逻辑移动到
LiveData对象,然后您将能够对onActiveonInactive回调做出反应。 -
您的意思是使用 liveData{} ktx?因为实际上这个协程每个循环都会调用
_someLiveData.value = ...。问题是,如果我将应用程序发送到后台,循环将继续。当然 UI 不会对此做出反应,但我们不应该避免循环的额外计算吗?
标签: android kotlin android-lifecycle kotlin-coroutines android-viewmodel