Jeff Johnson
05/06/2020, 5:43 PMView
that does not exist anymore.
open class CoroutineLauncher : CoroutineScope {
private val dispatcher: CoroutineDispatcher = Dispatchers.Main
private val supervisorJob = SupervisorJob()
override val coroutineContext: CoroutineContext
get() = dispatcher + supervisorJob
fun launch(action: suspend CoroutineScope.() -> Unit) = launch(block = action)
fun cancelCoroutines() {
supervisorJob.cancelChildren() //coroutineContext.cancelChildren() has same results
}
}
here is the usage
class MyFragment : Fragment {
val launcher = CoroutineLauncher()
fun onSomeEvent() {
launcher.launch {
val result = someSuspendFunction() // made suspend function by using withContext(<http://Dispatchers.IO|Dispatchers.IO>)
if (!isActive) return
// CAUSES CRASH
myTextView.text = result.userText
}
}
override fun onDestroyView() {
super.onDestroyView()
launcher.cancelCoroutines()
}
}
I added log lines to ensure onDestroyView
and cancelCoroutines
are both being called before the crash. It is my understanding that withContext
is cancellable and thus I shouldn’t even need to check for isActive
. I feel like I’m missing something obvious, but I can’t figure out what it isJoffrey
05/06/2020, 6:51 PMmyTextView
may not be available when you reach that line. If your coroutine is cancelled right before this call, it will still try to perform the assignment (cancellation is cooperative).
Maybe you should not try to update the UI from the `launch`’s context. Use a withContext
to ensure it runs on the UI thread.
Another way would be to use cancelAndJoin()
to make sure you wait for your coroutines to finish from onDestroyView
Jeff Johnson
05/06/2020, 7:44 PMmyTextView
is unavailable. My CoroutineLauncher
uses Dispatchers.Main
as its dispatcher so that should definitely run on the UI threadcancelChildren
is called before someSuspendFunction()
is even called. Which since withContext
is ‘cooperative’ should mean that the Text View ix never even accessedonSomeEvent
was being invoked after cancel was called. Since we call cancelChildren
instead of cancel
, the launcher does not refuse new Jobs, and since cancel already happened, the new coroutine runs like normal and crashesJoffrey
05/06/2020, 10:16 PM