For example,this view.When the onDetachedFromWindow
invoke the scope is cancelled,but the launched job is still active.
class TestView : FrameLayout,CoroutineScope {
val TAG = "TestView"
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + Job()
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
launch {
while (true) {
Log.i(TAG,"is in launch coroutine....${coroutineContext} ${[email protected]}")
delay(1000)
}
}
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
cancel()
Log.i(TAG,"onDetachedFromWindow")
}
}
the log is
2019-09-19 21:32:26.652 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@2f3fde2, Main]
2019-09-19 21:32:27.655 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@80a2573, Main]
2019-09-19 21:32:28.656 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@dad2c30, Main]
2019-09-19 21:32:29.649 22912-22912/com.ymr.myapplication I/TestView: onDetachedFromWindow
2019-09-19 21:32:29.665 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@dab39f4, Main]
2019-09-19 21:32:30.666 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@448351d, Main]
2019-09-19 21:32:31.668 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@45ba392, Main]
2019-09-19 21:32:32.669 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@bc75163, Main]
So why can't cancel the scope launched jobs?
Making computation code cancellable like the following example shows: val startTime = System. currentTimeMillis() val job = launch(Dispatchers. Default) { var nextPrintTime = startTime var i = 0 while (isActive) { // cancellable computation loop // print a message twice a second if (System.
The first method, cancel(jobId) , allows us to cancel a specific job using the job identifier returned from the schedule(JobInfo job) function or the jobId available on JobInfo objects returned by the getAllPendingJobs function.
When you call cancel() on the CoroutineScope , it's cancelling the internal Job . So to reuse the CoroutineScope , a new Job must be added to the context.
The issue is that you're creating a new Job
in coroutineContext
every time. You can fix this easily with
override val coroutineContext = Dispatchers.Main + Job()
However, please bear in mind that if your view is attached to window after being detached the coroutineContext
will already be cancelled.
Take a look at the following example to get a better picture of how it should work:
class MyActivity : AppCompatActivity(), CoroutineScope {
lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
}
override fun onDestroy() {
super.onDestroy()
job.cancel() // Cancel job on activity destroy. After destroy all children jobs will be cancelled automatically
}
/*
* Note how coroutine builders are scoped: if activity is destroyed or any of the launched coroutines
* in this method throws an exception, then all nested coroutines are cancelled.
*/
fun loadDataFromUI() = launch { // <- extension on current activity, launched in the main thread
val ioData = async(Dispatchers.IO) { // <- extension on launch scope, launched in IO dispatcher
// blocking I/O operation
}
// do something else concurrently with I/O
val data = ioData.await() // wait for result of I/O
draw(data) // can draw in the main thread
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With