viewModelScope 未取消

Gui*_*lhE 5 android android-lifecycle kotlin android-viewmodel kotlin-coroutines

在观看了Sean 在 Android (Google I/O'19) 上的解释后,我尝试了同样的方法:

init{
    viewModelScope.launch {
        Timber.i("coroutine awake")
        while (true){
            delay(2_000)
            Timber.i("another round trip")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,onCleared它在活动被终止时被调用,而不是在它被置于后台时调用(“当我们离开活动时......”,背景正在“移开”恕我直言^^)。
我得到以下输出:

> ---- 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
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

1 -从移动代码initsuspend 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()
    }
}
Run Code Online (Sandbox Code Playgroud)

而且,在我的活动中:

override fun onResume() {
    super.onResume()
    lifecycleScope.launch {
        viewModel.startEmitting()
    }
}
override fun onPause() {
    super.onPause()
    viewModel.cancelJob()
}
Run Code Online (Sandbox Code Playgroud)

嗯,它有效,但不是为我viewModelScope管理的目的CoroutineScope吗?我讨厌这种 cancelJob 逻辑。

处理这个问题的最佳方法是什么?

Jos*_*eca 5

Kotlin 无法为您取消无限操作。你需要打电话给isActive某个地方。例如:while(isActive)