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