Вопрос проверяет понимание того, как разные уровни архитектуры должны распределять ответственность при использовании потоков, корутин и асинхронных операций.
Обычно управление потоками делят между слоями так: presentation-слой отвечает за запуск корутин и управление жизненным циклом, domain-слой использует dispatcher’ы для выполнения бизнес-логики, а data-слой работает с сетью и базой данных на своих потоках. Такой подход упрощает тестирование, делает код предсказуемым и предотвращает утечки ресурсов. Каждый слой работает только с данными своего уровня, не нарушая границы архитектуры.
Многопоточность — важная часть архитектуры Android-приложений. Чтобы код оставался чистым и поддерживаемым, ответственность должна быть чётко распределена между слоями.
Основные задачи:
Запуск асинхронных операций, обычно в ViewModel.
Управление coroutine scope, привязанным к жизненному циклу UI (viewModelScope).
Переключение контекста в Main-поток для обновления UI.
Пример:
viewModelScope.launch {
val data = useCase()
state.value = data
}
Особенность слоя:
Presentation не должен заниматься сетевыми вызовами или обработкой SQL — только реакцией на пользовательские действия и отображением состояния.
Основные задачи:
Выполнение бизнес-логики на фоновых потоках.
Использование Dispatchers, передаваемых извне (например, через DI).
Гарантия, что use case никогда не блокирует основной поток.
Пример:
class LoginUseCase(
private val repository: AuthRepository,
private val dispatcher: CoroutineDispatcher
) {
suspend operator fun invoke() = withContext(dispatcher) {
repository.login()
}
}
Особенность слоя:
Domain не знает о UI и не управляет жизненными циклами.
Основные задачи:
Выполнение сетевых запросов в IO-диспетчере.
Обращение к базе данных также в IO-диспетчере.
Обработка больших данных и сериализация.
Пример:
suspend fun getUser(): UserDto = withContext(Dispatchers.IO) {
api.getUser()
}
Особенность слоя:
Data скрывает детали потоков и возвращает чистые модели domain-слою.
UI — только Main thread.
Domain — потоковая логика, но без привязки к конкретным Dispatchers.
Data — все тяжёлые операции, работа с IO.
Никто, кроме UI, не обновляет UI.
Никто, кроме data, не работает с сетью и базой данных.
Такой подход предотвращает смешивание ответственности и снижает риск ошибок.
Разделение потоковой логики между слоями делает приложение предсказуемым, легко тестируемым и менее подверженным ошибкам. Каждый слой выполняет только свою роль, не нарушая архитектурных границ.