Почему для сетевых запросов используют IO диспетчер в Android?
Что проверяют
Понимаете ли вы, почему главный поток нельзя блокировать, и чем пул для ожидания отличается от пула для вычислений. Хороший признак: кандидат сам говорит, что для приостанавливаемых функций Retrofit он не нужен.
Как отвечать
Главный поток рисует кадры и обрабатывает ввод. Бюджет кадра около шестнадцати миллисекунд: блокирующая операция на нём даёт пропуски кадров, а через несколько секунд система показывает диалог о зависании. Платформа это прямо запрещает и бросает NetworkOnMainThreadException.
Dispatchers.IO это пул под блокирующие операции: сокеты, файлы, хранилище настроек. Он рассчитан на то, что поток большую часть времени спит в ожидании, поэтому допустимый параллелизм у него намного больше числа ядер, потоки переиспользуются и делятся с Dispatchers.Default. У Default параллелизм по числу ядер, он для счётной работы: разбор большого ответа, сортировка, обработка изображения.
Правильная форма: приостанавливаемая функция репозитория сама делает себя безопасной для главного потока, а не перекладывает выбор на вызывающего.
suspend fun loadUser(id: String): User = withContext(ioDispatcher) {
api.getUserBlocking(id)
}Диспетчер стоит внедрять параметром, а не писать константой: в тестах тогда подставляется тестовый диспетчер.
Отдельно: если сетевой слой уже асинхронный, оборачивать не нужно. Приостанавливаемые функции Retrofit и запросы Room уходят со своего потока сами, лишняя обёртка добавляет только переключение контекста.
Где спотыкаются
Оборачивают всё подряд на всякий случай, включая вызовы Retrofit. Миф растёт из фразы «библиотека интегрирована с диспетчером ввода-вывода», хотя у клиента свой пул потоков, и внешняя обёртка ничего там не меняет.
Отправляют в пул ввода-вывода тяжёлые вычисления. Пул рассчитан на ожидание, десятки счётных корутин начинают конкурировать за ядра и мешают настоящим блокирующим задачам. Счётная работа идёт в Dispatchers.Default.
Запускают сетевой вызов в глобальной области. Корутина переживает экран, пишет результат в уже мёртвую модель и удерживает ссылки. Область должна умирать вместе с владельцем, отсюда viewModelScope и lifecycleScope.