Как гарантировать, что данные будут сохранены до того, как Android убьет процесс

В Android, как правило, рекомендуется не выполнять операции с базой данных (или, по крайней мере, сложные операции) в UI-Thread. У меня есть действие со сложной формой, и я хочу убедиться, что все данные сохраняются, когда действие выполняется в фоновом режиме (например, пользователь нажимает кнопку «Домой» или поступает телефонный звонок). В методе onPause() активности я могу запустить AsyncTask, который хранит данные в базе данных, но я никогда не могу быть уверен, что задача завершится успешно, потому что Android может убить процесс до завершения задачи, потому что активность и все приложение находятся в фоновом режиме .

Я могу сохранить синхронизацию данных в методе onPause, но тогда можно столкнуться с ANR.
Я знаю, что Android восстанавливает представления после того, как действие было уничтожено, но это работает правильно, только если идентификаторы просмотра уникальны. У меня есть много программно добавленных представлений, где я не могу гарантировать уникальность идентификатора, а использовать функцию saveInstanceState практически невозможно, потому что мне приходится сохранять очень сложные модели.

Есть ли возможность гарантировать, что данные будут сохранены до того, как андроид убьет процесс, не делая этого в UI-потоке?


person dan    schedule 08.05.2013    source источник


Ответы (4)


Однажды я создал приложение, в котором у меня были похожие проблемы с согласованностью данных. Что я сделал, так это делегировал хранение объектов данных службе, которую я создал только для этой цели. Хотя это значительно усложняет запуск/остановку/инициализацию вашей активности (после того, как активность будет запущена снова, вам придется подождать, пока служба завершит свое ранее запущенное действие сохранения), это был единственный способ «Android», который я мог подумайте, как справиться с этой проблемой.

person baske    schedule 08.05.2013
comment
Согласно API-документу Android, менее вероятно, но также возможно, что служба будет убита. Хорошо, я могу попытаться перезапустить службу, но чтобы данные были сохранены, я могу столкнуться с бесконечным циклом (я признаю, что это очень маловероятно, но не невозможно). На данный момент единственный способ сохранить данные и убедиться, что они сохранены в любом случае, — это сделать это в UI-Thread, что является действительно ужасным дизайном приложения. - person dan; 08.05.2013
comment
Я полностью согласен с вашим наблюдением о наихудшем сценарии, когда Android решает убить ваше приложение, даже если оно размещает службу. Это возможно, но в то же время (как вы упомянули) крайне маловероятно. Сохранение данных в потоке пользовательского интерфейса на самом деле НЕ гарантирует, что они сохраняются, потому что через несколько секунд пользователю может быть представлено сообщение ANR. Когда он затем решит убить ваше приложение, оно немедленно прекратит работу, даже не завершив действие сохранения. - person baske; 08.05.2013
comment
Кстати, как насчет этих историй: пользователь решает выключить свой телефон, пока ваш сервис сохраняет данные. Вы возьмете вейк-лок, чтобы предотвратить это? И даже со всем этим на месте: что вы будете делать, если батарея полностью сядет? Я привожу эти наблюдения, чтобы подчеркнуть один момент: насколько вы хотите быть уверены? Вы всегда должны анализировать компромисс между тем, чтобы сделать достаточно и сделать слишком много, чтобы предотвратить потерю данных. Насколько важны данные, с которыми вы работаете? ИМО, делегирование AsyncTask по-прежнему довольно опасно, но делегирование службе вполне безопасно. - person baske; 08.05.2013
comment
Спасибо за ваш последний комментарий, я думаю, что он очень хорошо резюмирует всю проблему. - person dan; 08.05.2013

Вы можете использовать для этого службу, если боитесь, что система убьет ваши фоновые процессы до их завершения. Это может быть чрезмерным, но определенно будет работать так, как ожидалось =) Просто погуглите «Учебник по обслуживанию Android», если вы не знаете, как их использовать.

-Сервисы не будут убиты, если вы этого не захотите!

person Alexander W    schedule 08.05.2013

Действительно, если вы используете AsyncTask в onPause(), Android может завершить процесс вашего приложения, не дожидаясь завершения рабочего потока. Но это не остановит процесс, если запущен Service. Таким образом, хорошим решением здесь является реализация логики синхронизации базы данных с использованием файла IntentService.

person Egor    schedule 08.05.2013
comment
Android убивает каждый Service через 30 минут и перезагружает его. По крайней мере, это то, что я заметил. Если Service использует кешированные данные, которые находятся в памяти, например, для синхронизации с внешним источником, будет ли ваше решение по-прежнему действительным? - person DroidBender; 08.05.2013
comment
@MartijnVanMierloo, IntentService не является хорошим решением для задачи, которая должна выполняться более 30 минут. - person Egor; 08.05.2013
comment
@ Егор, на самом деле, если вы спросите меня, это полный недостаток Android - убивать сервисы каждые 30 минут. Более того, он даже противоречит документации по Сервисам. На мой взгляд, IntentService — такое же хорошее решение, как и любой другой сервис (какой другой механизм вы бы выбрали в противном случае?) для задач, которые необходимо выполнять в течение произвольного периода времени (включая 30+ минут). Теперь я знаю, что вы можете запустить службу с приоритетом переднего плана, но мне это больше похоже на плацебо реализации, чем на концептуальную разницу. - person baske; 08.05.2013

Здесь я сталкиваюсь с тем же вопросом, когда сохранять данные: пока пользователь заполняет форму или когда действие приостанавливается. Также мы должны учитывать повороты экрана или другие события, которые могут привести к потере данных.

Вот что я нашел на сайте для разработчиков Android:

Для данных поставщика контента мы предлагаем, чтобы в действиях использовалась пользовательская модель редактирования на месте. То есть любые изменения, которые вносит пользователь, вносятся немедленно, без дополнительного шага подтверждения. Поддержка этой модели, как правило, заключается в соблюдении двух правил:

  • При создании нового документа резервная запись базы данных или файл для него создается немедленно. Например, если пользователь решит написать новое электронное письмо, новая запись для этого электронного письма будет создана, как только он начнет вводить данные, так что, если после этого он перейдет к какой-либо другой деятельности, это электронное письмо будет теперь появляются в списке черновиков.
  • Когда вызывается метод onPause() активности, он должен зафиксировать в резервном поставщике контента или в файле любые изменения, сделанные пользователем. Это гарантирует, что эти изменения будут видны любому другому действию, которое должно быть запущено. Вероятно, вам захочется еще более агрессивно фиксировать данные в ключевые моменты жизненного цикла вашей активности: например, перед началом новой активности, перед завершением вашей собственной активности, когда пользователь переключается между полями ввода и т. д.

Эта модель предназначена для предотвращения потери данных, когда пользователь перемещается между действиями, и позволяет системе безопасно завершать действие (поскольку системные ресурсы нужны где-то еще) в любое время после того, как оно было приостановлено. Обратите внимание, что это означает, что пользователь, нажимающий НАЗАД из вашей активности, не означает отмену — это означает выход из активности с сохраненным текущим содержимым. Отмена изменений в действии должна быть обеспечена с помощью какого-либо другого механизма, такого как явный параметр возврата или отмены.

person Alex    schedule 09.10.2014