isDispatchNeeded

open fun isDispatchNeeded(context: CoroutineContext): Boolean (source)

Returns true if execution shall be dispatched onto another thread. The default behaviour for most dispatchers is to return true.

UI dispatchers should not override isDispatchNeeded, but leave a default implementation that returns true. To understand the rationale beyond this recommendation, consider the following code:

fun asyncUpdateUI() = async(MainThread) {
    // do something here that updates something in UI
}

When you invoke asyncUpdateUI in some background thread, it immediately continues to the next line, while UI update happens asynchronously in the UI thread. However, if you invoke it in the UI thread itself, it updates UI synchronously if your isDispatchNeeded is overridden with a thread check. Checking if we are already in the UI thread seems more efficient (and it might indeed save a few CPU cycles), but this subtle and context-sensitive difference in behavior makes the resulting async code harder to debug.

Basically, the choice here is between “JS-style” asynchronous approach (async actions are always postponed to be executed later in the even dispatch thread) and “C#-style” approach (async actions are executed in the invoker thread until the first suspension point). While, C# approach seems to be more efficient, it ends up with recommendations like “use yield if you need to ….”. This is error-prone. JS-style approach is more consistent and does not require programmers to think about whether they need to yield or not.

However, coroutine builders like launch and async accept an optional CoroutineStart parameter that allows one to optionally choose C#-style CoroutineStart.UNDISPATCHED behaviour whenever it is needed for efficiency.