Как исправить проблему с записью данных при запросе
Что проверяют
Вопрос расплывчат намеренно: смотрят, начнёте ли вы с диагностики или сразу предложите «вынести в фоновый поток». Под «проблемой с записью» может скрываться падение, заморозка интерфейса, потерянные или задублированные данные. Следом обычно уточняют, что будет, если пользователь закроет экран посреди записи.
Как отвечать
Сначала спросите симптом и посмотрите Logcat, затем пройдите по типичным причинам:
- запись в главном потоке: Room по умолчанию бросает
IllegalStateExceptionпри обращении к базе из main thread. Решение:suspend-методы в DAO, их Room выполнит на своём пуле потоков, а остальной ввод-вывод черезwithContext(Dispatchers.IO); - отмена вместе с экраном: запись запущена в
viewModelScopeилиlifecycleScope, и корутина отменяется при уходе с экрана. То, что обязано дописаться, отдают вWorkManagerили в scope уровня приложения; - частичная запись: ответ сервера раскладывается по нескольким таблицам без транзакции. Помогает
@Transactionв DAO илиdb.withTransaction { }; - дубли: повторный запрос вставляет ту же запись. Нужен ключ из данных сервера и
@UpsertилиOnConflictStrategy.REPLACE, помня, чтоREPLACEудаляет старую строку и может каскадно снести связанные записи; - гонка при чтении и изменении: две корутины читают значение, увеличивают и пишут обратно. Лучше атомарный SQL
UPDATE ... SET count = count + 1илиMutex.
Для настроек вместо SharedPreferences сейчас берут DataStore, а если остаются SharedPreferences, то commit() пишет синхронно, apply() асинхронно.
Где спотыкаются
Советуют AsyncTask или голый Thread. AsyncTask объявлен устаревшим ещё в Android 11, а поток без привязки к жизненному циклу теряет результат и держит ссылки на уничтоженный экран.
Лечат симптом через allowMainThreadQueries(). Исключение пропадает, зато интерфейс подвисает на больших записях и ловит ANR.
Глотают исключения через catch (e: Exception) с printStackTrace(). Пользователь уверен, что данные сохранены, а их нет. Ошибка должна дойти до UI как состояние или привести к повтору, а CancellationException нужно пробрасывать дальше.