1 package kotlinx.coroutines
2 
3 import kotlinx.coroutines.internal.*
4 
5 /**
6  * Base class for special [CoroutineDispatcher] which is confined to application "Main" or "UI" thread
7  * and used for any UI-based activities. Instance of `MainDispatcher` can be obtained by [Dispatchers.Main].
8  *
9  * Platform may or may not provide instance of `MainDispatcher`, see documentation to [Dispatchers.Main]
10  */
11 public abstract class MainCoroutineDispatcher : CoroutineDispatcher() {
12 
13     /**
14      * Returns dispatcher that executes coroutines immediately when it is already in the right context
15      * (e.g. current looper is the same as this handler's looper) without an additional [re-dispatch][CoroutineDispatcher.dispatch].
16      *
17      * Immediate dispatcher is safe from stack overflows and in case of nested invocations forms event-loop similar to [Dispatchers.Unconfined].
18      * The event loop is an advanced topic and its implications can be found in [Dispatchers.Unconfined] documentation.
19      * The formed event-loop is shared with [Dispatchers.Unconfined] and other immediate dispatchers, potentially overlapping tasks between them.
20      *
21      * Example of usage:
22      * ```
23      * suspend fun updateUiElement(val text: String) {
24      *   /*
25      *    * If it is known that updateUiElement can be invoked both from the Main thread and from other threads,
26      *    * `immediate` dispatcher is used as a performance optimization to avoid unnecessary dispatch.
27      *    *
28      *    * In that case, when `updateUiElement` is invoked from the Main thread, `uiElement.text` will be
29      *    * invoked immediately without any dispatching, otherwise, the `Dispatchers.Main` dispatch cycle will be triggered.
30      *    */
31      *   withContext(Dispatchers.Main.immediate) {
32      *     uiElement.text = text
33      *   }
34      *   // Do context-independent logic such as logging
35      * }
36      * ```
37      *
38      * Method may throw [UnsupportedOperationException] if immediate dispatching is not supported by current dispatcher,
39      * please refer to specific dispatcher documentation.
40      *
41      * [Dispatchers.Main] supports immediate execution for Android, JavaFx and Swing platforms.
42      */
43     public abstract val immediate: MainCoroutineDispatcher
44 
45     /**
46      * Returns a name of this main dispatcher for debugging purposes. This implementation returns
47      * `Dispatchers.Main` or `Dispatchers.Main.immediate` if it is the same as the corresponding
48      * reference in [Dispatchers] or a short class-name representation with address otherwise.
49      */
toStringnull50     override fun toString(): String = toStringInternalImpl() ?: "$classSimpleName@$hexAddress"
51 
52     override fun limitedParallelism(parallelism: Int): CoroutineDispatcher {
53         parallelism.checkParallelism()
54         // MainCoroutineDispatcher is single-threaded -- short-circuit any attempts to limit it
55         return this
56     }
57 
58     /**
59      * Internal method for more specific [toString] implementations. It returns non-null
60      * string if this dispatcher is set in the platform as the main one.
61      * @suppress
62      */
63     @InternalCoroutinesApi
toStringInternalImplnull64     protected fun toStringInternalImpl(): String? {
65         val main = Dispatchers.Main
66         if (this === main) return "Dispatchers.Main"
67         val immediate =
68             try { main.immediate }
69             catch (e: UnsupportedOperationException) { null }
70         if (this === immediate) return "Dispatchers.Main.immediate"
71         return null
72     }
73 }
74