携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情
大家在使用协程的时候,对应Dispatchers.Main
并不陌生,将协程的上下文指定为Dispatchers.Main
,就代表协程代码块将在主线程中执行。但你有没有想过,Dispatchers.Main
底层是怎么实现这种能力的,即如何将协程代码放到主线程中执行的?Dispatchers.Main.immediate
又是用来干什么的?
本篇文章主要是回答三个问题:
Dispatchers.Main
是个啥?
Dispatchers.Main
是怎么实现的?
Dispatchers.Main
如何使用?
Dispatchers.Main.immediate
和Dispatchers.Main
又有啥区别?
Dispatchers.Main
是个啥?
这个问题很容易回答,通过打印Dispatchers.Main::class.simpleName
可知,Dispatchers.Main
就是个HandleContext
类的一个实例对象。
internal class HandlerContext private constructor(
private val handler: Handler,
private val name: String?,
private val invokeImmediately: Boolean
): HandlerDispatcher()
其中HandlerContext
的两个关键参数,在这里直接说结论:
-
handler
持有的mLooper
是主线程Looper.getMainLooper()
-
invokeImmediately
值为false,默认任何场景通过调度器分发到主线程执行(即使当前已经是主线程环境)
接下来我们一步步分析Dispatchers.Main
实现流程,以及上面两个参数在协程调度中怎样发挥作用。
Dispatchers.Main
是怎么实现的?
接下来进行Dispatchers.Main
的创建流程分析:
Dispatchers.Main
public actual object Dispatchers {
@JvmStatic
public actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher
}
MainDispatcherLoader.dispatcher
@JvmField
val dispatcher: MainCoroutineDispatcher = loadMainDispatcher()
private fun loadMainDispatcher(): MainCoroutineDispatcher {
return try {
val factories = if (FAST_SERVICE_LOADER_ENABLED) {
FastServiceLoader.loadMainDispatcherFactory()
} else {
ServiceLoader.load(
MainDispatcherFactory::class.java,
MainDispatcherFactory::class.java.classLoader
).iterator().asSequence().toList()
}
factories.maxByOrNull { it.loadPriority }?.tryCreateDispatcher(factories)
?: createMissingDispatcher()
}
}
不管FAST_SERVICE_LOADER_ENABLED
为true还是false,最终都是创建一个实现了MainDispatcherFactory
接口的AndroidDispatcherFactory
类型的实例对象。
PS: 当
FAST_SERVICE_LOADER_ENABLED
为true,是通过反射创建的AndroidDispatcherFactory
;为false,则是通过java的SPI服务发现机制
创建的AndroidDispatcherFactory
。ServiceLoader.load
会读取META-INF/services/kotlinx.coroutines.internal.MainDispatcherFactory
文件:
接下来分析AndroidDispatcherFactory
。
AndroidDispatcherFactory
internal class AndroidDispatcherFactory : MainDispatcherFactory {
override fun createDispatcher(allFactories: List<MainDispatcherFactory>): MainCoroutineDispatcher {
val mainLooper = Looper.getMainLooper() ?: throw IllegalStateException("The main looper is not available")
return HandlerContext(mainLooper.asHandler(async = true))
}
最终调用其createDispatcher()
方法创建了HandlerContext
:
- 获取主线程
Looper
并调用asHandler()
扩展方法创建一个异步Handler
对象:
internal fun Looper.asHandler(async: Boolean): Handler {
if (!async || Build.VERSION.SDK_INT < 16) {
return Handler(this)
}
//28及以上提供了createAsync创建异步Handler
if (Build.VERSION.SDK_INT >= 28) {
val factoryMethod = Handler::class.java.getDeclaredMethod("createAsync", Looper::class.java)
return factoryMethod.invoke(null, this) as Handler
}
//通过构造方法创建异步Handler
val constructor: Constructor<Handler>
try {
constructor = Handler::class.java.getDeclaredConstructor(Looper::class.java,
Handler.Callback::class.java, Boolean::class.javaPrimitiveType)
} catch (ignored: NoSuchMethodException) {
return Handler(this)
}
return constructor.newInstance(this, null, true)
}
这个创建异步Handler
扩展考虑的非常全面标准,包括了对各个变动版本的适配,大家可以考虑把这个扩展移植到自己项目中使用。
- 构造
HandlerContext
handler的Looper就是主线程Looper
,invokeImmediately
赋值false。
我们看下HandlerContext
的继承链:
stateDiagram-v2
[*] --> HandlerContext
HandlerContext --> HandlerDispatcher
HandlerDispatcher --> MainCoroutineDispatcher
MainCoroutineDispatcher --> CoroutineDispatcher
CoroutineDispatcher --> ContinuationInterceptor
ContinuationInterceptor --> [*]
属于协程四大上下文元素之一的分发器。
总结
我们先回答一开始提出的前两个问题:
-
Dispatchers.Main
是个HandlerContext
对象 -
HandlerContext
是被AndroidDispatcherFactory
创建的,而AndroidDispatcherFactory
是通过SPI或者反射创建的,其中参数invokeImmediately
为false,handler
分发消息到主线程。
接下来还有一篇文章分析HandlerContext
在协程源码中是如何进行运用的。