我们把关于contexts\children
和jobs
的知识融合到一起,试想我们有一个具备生命周期的对象,但这个对象不是一个协程。例如,在开发Android应用时,为了执行获取网络数据、执行动画等异步操作,我们在activity的里开启了各种协程。为了避免内存泄漏,当activity被销毁时,所有的这些协程必须取消。
通过创建一个Job
的实例来控制我们协程的生命周期,把它绑定到activity的生命周期上。在activity被创建时,使用工厂方法Job()
创建一个job实例;当activity被销毁时,它如下这样被取消:
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
}
}
这个activity实现了CoroutineScope接口,我们只需要重写CoroutineScope.coroutineContext属性来指定协程在这个scope
内的执行上下文环境context
。那么在这个activity里启动协程就不需要再明确指定他们的执行环境context。
这里有一段示意代码
import kotlin.coroutines.*
import kotlinx.coroutines.*
class Activity : CoroutineScope {
lateinit var job: Job
fun create() {
job = Job()
}
fun destroy() {
job.cancel()
}
// to be continued ...
// class Activity continues
override val coroutineContext: CoroutineContext
get() = Dispatchers.Default + job
// to be continued ...
// class Activity continues
fun doSomething() {
// launch ten coroutines for a demo, each working for a different time
repeat(10) { i ->
launch {
delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
println("Coroutine $i is done")
}
}
}
} // class Activity ends
fun main() = runBlocking<Unit> {
val activity = Activity()
activity.create() // create an activity
activity.doSomething() // run test function
println("Launched coroutines")
delay(500L) // delay for half a second
println("Destroying activity!")
activity.destroy() // cancels all coroutines
delay(1000) // visually confirm that they don't work
}
//Launched coroutines
//Coroutine 0 is done
//Coroutine 1 is done
//Destroying activity!
相关概念
协程,是线程中的,也就是说一个线程中可能包含多个协程,协程与协程之间是可以嵌套的
-
Scope
用来给协程分组,在同一个CoroutineScope下创建的协程(如果没有显示指定其他Scope),默认都是父子关系,这样的好处在于cancel父协程后,所有的子协程都可以被一起cancel掉。
-
Context
当前协程的上下文,用于在协程与协程之间参数传递。
可以用于声明当前 协程 在哪一个线程中声明,以及当前 协程 被中断后,在哪一个线程中恢复它
-
Job
代表了协程本身,协程不仅包含了上下文,其本身还是可执行体。
任务,封装了协程中需要执行的代码逻辑。Job 可以取消并且有简单生命周期 -
Dispatcher
调度器,调度协程运行在哪个线程上。决定协程所在的线程或线程池。它可以指定协程运行于特定的一个线程、一个线程池或者不指定任何线程(这样协程就会运行于当前线程)
-
withcontext
不会创建新的协程,在指定协程上运行挂起代码块,并挂起该协程直至代码块运行完成
网友评论