Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

throw kotlinx.coroutines.JobCancellationException when go to another screen

Android Studio 3.6

on one screen I polling by coroutine like this:

 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"
                )
            } 
        }

In transport service:

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

In Activity :

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

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

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

It work fine. But when I go to another screen (Activity) it throw

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

After go to another screen I need to stop polling.

like image 602
Alexei Avatar asked Feb 12 '20 09:02

Alexei


Video Answer


1 Answers

Your current implementation of coroutine is bounded to the lifecycle of ViewModel, and viewModelScope cancels after ViewModel has been cleared up (what is happening after you open another Activity).

So if your goal is to stop polling bonuses after you navigate to another Activity you don't need to implicitly stop the coroutine with poll.cancel(), just let viewModelScope do it's job. Otherwise, if you want to continue polling after ViewModel is cleared, consider using some upper (probably Global) scope.

If you want to avoid JobCancellationException in your code - instead of try/catch consider using CoroutineExceptionHandler as an addition to your coroutine context, it's designed to handle uncaught exceptions in coroutines and ignore cancelled exceptions.

like image 96
Alex Krafts Avatar answered Nov 09 '22 03:11

Alex Krafts