viewModelScope не отменен - PullRequest
       36

viewModelScope не отменен

1 голос
/ 25 сентября 2019

После просмотра объяснения Шона на Android (Google I / O'19) Я пробовал то же самое:

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

К сожалению onCleared вызывается, когда действие прекращаетсяно не тогда, когда он находится в фоновом режиме («когда мы отходим от действия ...», фон «уходит» imho ^^).
И я получаю следующий вывод:

> ---- 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 для меня?Я ненавижу эту логику отмены работы.

Как лучше всего с этим справиться?

Ответы [ 2 ]

1 голос
/ 25 сентября 2019

Kotlin не может отменить бесконечную операцию для вас.Вам нужно позвонить isActive куда-нибудь.Например: while(isActive).

0 голосов
/ 25 сентября 2019

Вы можете написать свой собственный класс LiveData вместо использования MutableLiveData.

Когда вы сделаете это, вы можете переопределить методы, которые явно уведомят вас о наличии активных слушателей.

class MyViewModel : ViewModel(){
    val liveData = CustomLiveData(viewModelScope)

    class CustomLiveData(val scope) : LiveData<Int>(){
        private counter = 0
        private lateinit var job: Job

        override fun onActive() {
            job = scope.launch {
                Timber.i("coroutine awake")
                while (true){
                    delay(2_000)
                    Timber.i("another round trip")
                    postValue(counter++)
                }
        }

        override fun onInactive() {
            job.cancel()
        }
    }
}

Тогда внутри вашего Activity вам больше не нужно явно вызывать любой запуск / паузу, так как LiveData автоматически начнет и отменит сопрограмму в зависимости от состояния наблюдателей.

...