- package kotlinx.coroutines
- ...
- public actual object Dispatchers {
- ...
- @JvmStatic
- public actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher
- ...
- }
- package kotlinx.coroutines
- ...
- public abstract class MainCoroutineDispatcher : CoroutineDispatcher() {
- ...
- public abstract val immediate: MainCoroutineDispatcher
- ...
- }
- package kotlinx.coroutines.android
- ...
- public sealed class HandlerDispatcher : MainCoroutineDispatcher(), Delay {
- ...
- public abstract override val immediate: HandlerDispatcher
- }
- package kotlinx.coroutines.android
- ...
- internal class HandlerContext private constructor(
- private val handler: Handler,
- private val name: String?,
- private val invokeImmediately: Boolean
- ) : HandlerDispatcher(), Delay {
- ...
- @Volatile
- private var _immediate: HandlerContext? = if (invokeImmediately) this else null
- override val immediate: HandlerContext = _immediate ?:
- HandlerContext(handler, name, true).also { _immediate = it }
- override fun isDispatchNeeded(context: CoroutineContext): Boolean {
- return !invokeImmediately || Looper.myLooper() != handler.looper
- }
- ...
- }
invokeImmediately は isDispatchNeeded() で使われます。isDispatchNeeded() の実装をみると、invokeImmediately が false のときは常に isDispatchNeeded() が true を返すことがわかります。また Looper.myLooper() != handler.looper のときも isDispatchNeeded() が true を返すことがわかります。つまり、invokeImmediately が true かつ Looper.myLooper() == handler.looper のときだけ isDispatchNeeded() は false を返します。
このことから、immediate にセットされる HandlerContext では、Looper.myLooper() が handler.looper と同じだと isDispatchNeeded() が false を返すということがわかります。
isDispatchNeeded() は coroutine を dispatch メソッドで実行するべきかどうか判定するときに呼ばれます。デフォルトは true を返すようになっています。
- package kotlinx.coroutines
- ...
- public abstract class CoroutineDispatcher :
- AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
- ...
- public open fun isDispatchNeeded(context: CoroutineContext): Boolean = true
- ...
- }
つまり、(kotlinx-coroutines-android の) Dispatchers.Main.immediate はすでに UI スレッドにいる場合(現在の Looper.myLooper() が handler.looper と同じ場合)そのまますぐに実行される Dispatcher ということです。
例えば Dispatchers.Main を使った以下のコードだと
- class MainActivity : AppCompatActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- CoroutineScope(Dispatchers.Main).launch {
- println("1 : ${Thread.currentThread().name}")
- }
- println("2 : ${Thread.currentThread().name}")
- }
- }
- I/System.out: 2 : main
- I/System.out: 1 : main
- class MainActivity : AppCompatActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- CoroutineScope(Dispatchers.Main.immediate).launch {
- println("1 : ${Thread.currentThread().name}")
- }
- println("2 : ${Thread.currentThread().name}")
- }
- }
- I/System.out: 1 : main
- I/System.out: 2 : main
- class MainActivity : AppCompatActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- CoroutineScope(Dispatchers.Default).launch {
- println("3 : ${Thread.currentThread().name}")
- CoroutineScope(Dispatchers.Main.immediate).launch {
- println("1 : ${Thread.currentThread().name}")
- }
- println("4 : ${Thread.currentThread().name}")
- }
- println("2 : ${Thread.currentThread().name}")
- }
- }
- I/System.out: 2 : main
- I/System.out: 3 : DefaultDispatcher-worker-2
- I/System.out: 4 : DefaultDispatcher-worker-2
- I/System.out: 1 : main
viewModelScope, lifecycleScope は dispatcher として Dispatchers.Main.immediate が指定されています。
- val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope
- get() = lifecycle.coroutineScope
- val Lifecycle.coroutineScope: LifecycleCoroutineScope
- get() {
- while (true) {
- ...
- val newScope = LifecycleCoroutineScopeImpl(
- this,
- SupervisorJob() + Dispatchers.Main.immediate
- )
- ...
- }
- }
- val ViewModel.viewModelScope: CoroutineScope
- get() {
- ...
- return setTagIfAbsent(JOB_KEY,
- CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))
- }