Комментарии 8
Большое спасибо, монументальная статья!
Огромное спасибо, статья космос
Много написано про подкапотную часть корутин, но эта статья наконец раскладывает нутнянку по полкам. Спасибо, добавил в сохраненные.
Поправьте fetchProfileInfo и fetchProfileData
Отличная статья, огромный объем работ проделан.
Но возник вопрос по этому примеру и пришлось смотреть сорсы.
/*
Dispatchers.Main всегда переключает выполнение корутины
на главный поток через Handler.post() механизм,
даже если корутина и так выполняется на главном
*/
val uiScope = CoroutineScope(Dispatchers.Main + Job())
uiScope.launch {
launch {
println("I'm child coroutine #1")
}
launch {
println("I'm child coroutine #2")
}
println("I'm parent coroutine")
}
В этом примере возникает вопрос, а как в итоге завершится parent coroutine, если во время ее resumeWith
дочерние корутины еще не завершены и она завершиться не может.
Как и кто в итоге вызовет ее resumeWith
, учитывая что вы упомянули что дочерние корутины не знают про ее continuation?
Объект
Continuation
родительской корутины никак не связан сContinuation
объектами дочерних корутин, поэтому когда завершатся последние результат не будет проброшен обратно вUiScopeParentBlock
, да и в этом особо нет смысла, как например сwithContext()
, который гарантирует последовательный порядок выполнения с возвращением результата.
Ответом будет подписка на Job
дочерних корутин, которая как раз и вызовет метод финализации стейта нашей корутины при последнем onCompletion
.
При этом resumeWith
не будет вызван повторно, но стейт корутины корректно финализируется
private tailrec fun tryWaitForChild(state: Finishing, child: ChildHandleNode, proposedUpdate: Any?): Boolean {
val handle = child.childJob.invokeOnCompletion(
invokeImmediately = false,
handler = ChildCompletion(this, state, child, proposedUpdate)
)
if (handle !== NonDisposableHandle) return true // child is not complete and we've started waiting for it
val nextChild = child.nextChild() ?: return false
return tryWaitForChild(state, nextChild, proposedUpdate)
}
Возможно, полезно будет добавить или упомянуть этот момент
Вот здесь ошибка:
// (5)
fun resumeWith(result: Result) {
try {
val newResult = invokeSuspend(result)
if (newResult === COROUTINE_SUSPENDED) return
Result.success(newResult)
} catch (exception: Throwable) {
Result.failure(exception)
}
completion.resumeWith(newResult)
}
Какой result всё-таки возвращает invokeSuspend (варианты помимо COROUTINE_SUSPENDED). Если это будет оно, то когда вызовется resumeWith?
Result.success и Result.failure надо присвоить в новую переменную для completion.resumeWith, newResult вообще не того типа и под try {}
Всё-таки я не понял, чем является completion, переданный в конструктор этого сгенерированного класса.
Огромное спасибо!
Kotlin Coroutines под капотом