转到另一个屏幕时抛出kotlinx.coroutines.JobCancellationException

时间:2020-02-12 09:36:13

标签: android kotlin-coroutines

Android Studio 3.6

在一个屏幕上,我像这样通过协程进行轮询:

 fun initPoll() =       
        viewModelScope.launch(Dispatchers.Main) {
            var errorMessage = ""
            try {
                while (true) {
                    val balanceValue: BigDecimal = TransportService.getBonuse()
                    delay(1000)
                }
            } catch (e: CancellationException) {
                Debug.e(
                    TAG,
                    "initPoll: error_message = ${e.message}, ex = $e"
                )
            } catch (e: Throwable) {
                Debug.e(
                    TAG,
                    "initPoll: error_message = ${e.message}, ex = $e"
                )
            } 
        }

在运输服务中:

suspend fun getBonuse() =
            withContext(Dispatchers.IO) {
                // some code here
            } // Dispatchers.Main

活动中:

import kotlinx.coroutines.*
private lateinit var poll: Job

 override fun onPause() {
        super.onPause()
        poll.cancel()
    }

    override fun onResume() {
        super.onResume()
        poll = mainViewModel.initPoll()
    }

工作正常。但是当我转到另一个屏幕(活动)时,它会抛出

02-12 11:34:17.115 E/com.myproject.MainViewModel(17685): initPoll: error_message = StandaloneCoroutine was cancelled, ex = kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job=StandaloneCoroutine{Cancelling}@aa5d4a1

转到另一个屏幕后,我需要停止轮询。

2 个答案:

答案 0 :(得分:3)

您当前的协程实现受限于ViewModel和viewModelScope cancels after ViewModel has been cleared up(打开另一个Activity后发生的情况)的生命周期。

因此,如果您的目标是在导航到另一个活动后停止轮询奖金,则不需要用poll.cancel()隐式停止协程,只需让viewModelScope即可。否则,如果您希望在清除ViewModel之后继续轮询,请考虑使用某些较高的范围(可能是全局范围)。

如果您想避免在代码中使用JobCancellationException-而不是try / catch,请考虑使用CoroutineExceptionHandler作为协程上下文的补充,它旨在处理协程中未捕获的异常并忽略已取消的异常。

答案 1 :(得分:0)

在我的情况下,滚动带有分页的RecyclerView时,出现了异常“ kotlinx.coroutines.JobCancellationException:StandaloneCoroutine被取消”。当它加载了下一页数据时,我单击了一个项目。它启动了coroutineContext.cancelChildren()并开始了另一个请求。

因此,当我尝试加载新的项目部分时,它取消了请求并落入try-catch

相关问题