通过Kotlin协程介绍(二)我们知道协程会将挂起函数(suspend函数)在编译期转换为CPS,suspend函数只能在协程或者另一个suspend中运行,那么如何创建一个协程呢?
CoroutineScope.launch
可以通过GlobalScope.launch创建并立即启动一个协程
GlobalScope.launch {
val start = System.currentTimeMillis()
println("start")
delay(1000) //协程内可以调用suspend函数
println("end ${System.currentTimeMillis() - start}")
}
我们看一下launch的函数定义
public fun CoroutineScope.launch(
context: CoroutineContext,
start: CoroutineStart,
block: suspend CoroutineScope.() → Unit
): Job
launch是一个CoroutineScope的扩展函数,CoroutineScope代表协程的作用域,持有一个CoroutineContext。coroutineContext类似Thread-local的概念,用于在协程中共享某些环境变量。
public interface CoroutineScope {
public abstract val coroutineContext: kotlin.coroutines.CoroutineContext
}
launch的第一个参数接受一个CoroutineDispatcher(CoroutineContext的子类),通过CoroutineDispatcher可以指定运行协程的线程或者线程池。例如,我们可以通过Dispatcher指定协程运行在Android主线程,执行到delay时,协程挂起,Android主线程不会被阻塞,待delay执行结束会,协程将回复在主线程的执行。
launch(UI) { //UI是kotinx-coroutine-android提供的Dispatcher,协程会被分派到UI线程执行
prograssBar.isVisible = true
delay(1000)
prograssBar.isVisible = false
}
Job
launch启动协程后返回一个Job代表当前协程的句柄,通过Job.cancel()可以停止协程的运行。协程内可以启动子协程,子协程的Job通过Job.attachChild关联到父协程的Job,父Job的cancel会取消所有子协程。每个CoroutineScope都有一个根节点Job,其内部launch的所有协程都是其子Job。我可以自定义CoroutineScope,通过根Job管理所有协程的生命周期,比如在android的viewmodel中,我们可以在viewmodel的onCleared时cancel其所有子协程
class MyViewModel : ViewModel() {
private val viewModelJob = SupervisorJob()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
override fun onCleared() {
super.onCleared()
viewModelJob.cancel() // Cancel 当前scope下的所有协程
}
fun launchDataLoad() {
uiScope.launch {
sortList()
}
}
suspend fun sortList() = withContext(Dispatchers.Default) {
// Heavy work
}
}