关于Android LifecycleScope的一点点发现
例子
代码的运行顺序应该是one()
,two()
还是two()
,one()
,或者是两个调用的时机是随机的,看协程的调度呢?相信很多人都会选择最后一个.但实际无论运行多少次都是下面的结果
并且launch()
方法传入的suspend 函数甚至会阻塞主线程,怎么回事儿,这个协程是假的协程?吗!
先说结论
Kotlin的协程在不同的平台有不同的实现方式.本文以我最熟悉的Android平台为例.在Android中,启动一个协程使用Dispatcher.Main.immediate
作为调度器的话,如果当前线程是主线程,就会将任务立即在主线程执行,如果是在其它线程中,使用Handler.post()
方法分给主线程去执行.
如果是Dispatcher.Main
作为调度器,就会直接使用主线程的Handler.post()
去执行.
CoroutineDispatcher:协程调度器
在导入了androidx.lifecycle:lifecycle-runtime-ktx
依赖后,可以在Activity中使用lifecycleScope.launch{}
启动一个协程,这里默认的上下文就是 EmptyCoroutineContext
,因此启动的协程上下文就是
kotlin
lifecycleScope.coroutineContext+EmptyCoroutineContext
看下lifecycleScope
是怎么来的
这样lifecycleScope.launch{}
这样启动一个协程默认的调度器就是Dispatcher.Main.immediate
Dispatcher顾名思义就是调度器,在这里就是负责协程的调度功能,导入依赖查看Android平台的Disptcher.Main
的最终实现是由HandlerContext
实现的
HandlerContext
重写了isDispatchNeeded
方法
查看isDispatchNeeded
的注释可知道如果该方法返回true就会通过dispatch()
将协程分发出去,false就会令协程在当前线程恢复,因此Disptcher.Main
会始终调用dispather()
来进行分发,而Dispatcher.Main.immediate
只有在非主线程中会调用dispatch()
.何时会调用CoroutineDispatcher.isDispatchNeeded()
方法呢?通过查看函数调用在DispatchedContinuation.resumeWith()
方法中使用到了它.
DispatchedContinuation:协程调度的发起者
这里只关注DispatchedContinuation
是如何让协程立即在当前线程恢复的逻辑
executeUnconfined()
方法是DispatchedContinuation
的一个拓展函数,协程的执行是交给EventLoop处理,它类似Handler的MessageQueue,如果当前线程的队列已满就会使用EventLoop.dispatchUnconfined()
将这个协程调度到当前的EventLoop中,否则直接调用runUnconfinedEventLoop()
将协程执行