Где корректно изменять данные из репозитория в Android приложении
Что проверяют
Знаете ли вы принцип единого источника правды и однонаправленного потока данных из официального гайда по архитектуре Android. Следом почти всегда спрашивают, что будет с сохранением, если пользователь закрыл экран посреди операции.
Как отвечать
Короткий ответ: данные меняет тот слой, который ими владеет, то есть репозиторий или источник данных за ним. Остальные слои только просят об изменении.
- UI: отправляет событие во
ViewModelи ничего не меняет сам; ViewModel: вызывает метод репозитория или use case из доменного слоя и отражает результат вStateFlowс состоянием экрана. Список, полученный из репозитория, она руками не правит;- репозиторий: единственная точка записи. Отдаёт данные наружу неизменяемыми, например
Flow<List<User>>из Room, и предоставляет методы вродеsuspend fun updateUser(user: User). После записи в базу подписчики получают новое значение автоматически; - модели:
data classс полямиval, изменение черезcopy(). Мутабельный объект, разошедшийся по слоям, меняется у всех сразу и незаметно; - потоки: suspend-функции репозитория должны быть безопасны для главного потока, переключение через
withContext(ioDispatcher)делается внутри репозитория, а не воViewModel.
Отдельно про жизненный цикл: viewModelScope отменяется, когда экран уходит. Операцию, которая обязана завершиться (отправка заказа, синхронизация), запускают во внешнем CoroutineScope, внедрённом в репозиторий, или отдают WorkManager, если она должна пережить даже смерть процесса.
Где спотыкаются
Меняют данные прямо в UI или в адаптере списка, а потом удивляются, что после поворота экрана изменения пропали.
Держат в репозитории MutableStateFlow и отдают его наружу как есть. Любой потребитель может записать туда что угодно, наружу нужно отдавать StateFlow через asStateFlow().
Запускают сохранение в viewModelScope и теряют запись при быстром закрытии экрана. Интервьюер обычно ждёт упоминания внешнего scope или WorkManager.