上一篇写协程的概念,这节将介绍协程的一些细节
先来看看相关的几个类或接口
//协程域
public interface CoroutineScope {
//这个协程域的上下文
public val coroutineContext: CoroutineContext
}
这个协程域中中包含了协程上下文,即这个域中存在一个,CoroutineContext:
async(Dispatchers.IO) {
coroutineContext.plus()// 可以操作上下文plus加法操作符
log(" "Show data in UI"")
}
Dispatchers.IO也是一个CoroutineContext
CoroutineScope by MainScope() 委托MainScope实现CoroutineScope 的上下文:
public fun MainScope(): CoroutineScope = ContextScope(SupervisorJob() + Dispatchers.Main)
线程调度(Dispatchers and threads)
private fun asyncShowData() = launch {
launch { // context of the parent, main runBlocking coroutine,默认受父协程上下文的限制,阻塞父协程
log("main runBlocking : I'm working in thread ${Thread.currentThread().name}")
}
launch(Dispatchers.Unconfined) { // not confined -- will work with main thread,没有任何限制,将在main线程运行
log("Unconfined : I'm working in thread ${Thread.currentThread().name}")
}
launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher,在DefaultDispatcher线程中运行
log("Default : I'm working in thread ${Thread.currentThread().name}")
}
launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread,在自定义线程中运行
log("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
}
}
打印日志:
[main]: Unconfined : I'm working in thread main
[DefaultDispatcher-worker-1]: Default : I'm working in thread DefaultDispatcher-worker-1
[MyOwnThread]: newSingleThreadContext: I'm working in thread MyOwnThread
[main]: main runBlocking : I'm working in thread main
没有受限制和受限制的协程(Unconfined vs confined dispatcher)
private fun asyncShowData() = launch {
launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
log("Unconfined : I'm working in thread ${Thread.currentThread().name}")
delay(500)
log("Unconfined : After delay in thread ${Thread.currentThread().name}")
}
launch { // context of the parent, main runBlocking coroutine
log("main runBlocking: I'm working in thread ${Thread.currentThread().name}")
delay(1000)
log("main runBlocking: After delay in thread ${Thread.currentThread().name}")
}
}
日志
Unconfined : I'm working in thread main
[main]: main runBlocking: I'm working in thread main
[kotlinx.coroutines.DefaultExecutor]: Unconfined : After delay in thread kotlinx.coroutines.DefaultExecutor
[main]: main runBlocking: After delay in thread main
当没有受限制的线程在delay后,后面程序将运行在kotlinx.coroutines.DefaultExecutor,默认是调度线程池中;
切换上下文(Jumping between threads)
private fun asyncShowData() = launch {
newSingleThreadContext("Ctx1").use { ctx1 ->
newSingleThreadContext("Ctx2").use { ctx2 ->
runBlocking(ctx1) {
log("Started in ctx1")
withContext(ctx2) {
log("Working in ctx2")
}
log("Back to ctx1")
}
}
}
}
日志
[Ctx1]: Started in ctx1
[Ctx2]: Working in ctx2
[Ctx1]: Back to ctx1
CoroutineContext 的Job(Job in the context)
private fun asyncShowData() = launch {
log("My job is ${coroutineContext[Job]}")
}
日志
[main]: My job is StandaloneCoroutine{Active}@2b26878e
父协程和子协程(Children of a coroutine)
/**
* 取消父协程,会把所有的子协程给取消
*/
private fun asyncShowData() = launch {
val request = launch {
//不受request协程的影响
GlobalScope.launch {
log("job1: I run in GlobalScope and execute independently!")
delay(1000)
log("job1: I am not affected by cancellation of the request")
}
//该协程的上下文默认使用request的上下文,受request的影响,所以改协程是request的子协程
launch {
delay(100)
log("job2: I am a child of the request coroutine")
delay(1000)
log("job2: I will not execute this line if my parent request is cancelled")
}
}
delay(500)
request.cancel() // 取消request协程
delay(1000)
log("main: Who has survived request cancellation?")
}
日志
[DefaultDispatcher-worker-1]: job1: I run in GlobalScope and execute independently!
[main]: job2: I am a child of the request coroutine
[DefaultDispatcher-worker-1]: job1: I am not affected by cancellation of the request
[main]: main: Who has survived request cancellation?
使用join等待所有的子协程完成
private fun asyncShowData() = launch {
log("parent start")
val job = launch {
log("1child start")
launch {
log("2child start")
delay(8000)
log("2child complete")
}
delay(5000)
log("1child complete")
}
job.join()
log("parent end")
}
日志
[main]: cancel
[main]: parent start
[main]: 1child start
[main]: 2child start
[main]: 1child complete
[main]: 2child complete
[main]: parent end
结合上下文元素(Combining context elements)
val newJob = Job()
val job = launch(Dispatchers.Default + newJob) {
log("start")
delay(5000)
log("I'm working in thread ${Thread.currentThread().name}")
}
log("${newJob == job} ${newJob} ${job}")
newJob.cancel()
可以看到newJob也可以操作该协程的状态
下一篇文章将是使用协程尝试构建MVP
网友评论