Что нужно для запуска корутины
Что проверяют
Знаете ли вы минимальный набор сущностей и понимаете ли структурированную конкурентность. Вопрос звучит просто, но продолжение всегда одно и то же: кто эту корутину отменит и на каком потоке выполнится её код.
Как отвечать
Нужны три вещи: область (CoroutineScope), билдер (launch или async) и контекст с диспетчером и Job. Тело билдера это suspend-блок, поэтому внутри доступны delay и другие suspend-функции.
viewModelScope.launch {
val data = withContext(Dispatchers.IO) { repository.load() }
render(data)
}В Android свою область почти никогда не создают руками, берут готовую, привязанную к жизненному циклу: viewModelScope во ViewModel, lifecycleScope на экране, а для сбора потоков repeatOnLifecycle. Тогда отмена происходит сама, когда владелец умирает.
Что ещё стоит сказать:
- диспетчер решает, где выполняется код:
Mainдля интерфейса,IOдля блокирующих вызовов,Defaultдля расчётов; suspend funсама корутину не запускает, её можно вызвать только из корутины или из другой suspend-функции;- ошибки: исключение в
launchидёт вверх по дереву и роняет родителя, если это обычныйJob;SupervisorJobизолирует детей, а уasyncисключение всплывает наawait.
Где спотыкаются
Создают CoroutineScope прямо на экране или в репозитории и не отменяют его. Корутина переживает владельца, держит на него ссылку и даёт утечку, а обращение к уничтоженному интерфейсу приводит к падению.
Думают, что смена диспетчера делает блокирующий код неблокирующим. Dispatchers.IO просто даёт другой пул: синхронное чтение файла или сон потока так же занимают поток, и на потоке запросов пул заканчивается.
Ставят try/catch вокруг вызова launch и ждут, что он поймает ошибку из тела. Билдер возвращает управление сразу, исключение случится позже и в другом месте, поэтому перехват пишут внутри блока или вешают обработчик на область.