onSaveInstanceState/onPause — ждать, пока состояние не будет полностью сохранено, прежде чем разрешать завершение процесса

Я работаю над своим первым приложением для Android. У него есть модель, которая сохраняется в базе данных по мере того, как пользователь вносит обновления.

Когда вызывается onSaveInsanceState, я хочу сохранить идентификатор, который можно использовать для загрузки документа, над которым работал пользователь, из базы данных. Но это может произойти только после того, как документ полностью попал в базу данных. В некоторых случаях сохранение сложного документа может занять несколько секунд (я надеюсь, что это ускорится, когда я выполню весь подробный выход из системы, и в реальном использовании сложный документ будет создаваться пользователем поэтапно, каждый из которых будут сохранены в базе данных, поэтому маловероятно, что сложный документ нужно будет сохранять за один раз).

Теперь правило №1 многопоточности на Android — «не блокировать поток пользовательского интерфейса», поэтому, конечно, взаимодействие с БД происходит в отдельном потоке. Но мое понимание жизненного цикла Android заключается в том, что во многих случаях onSaveInstanceState вызывается, потому что система Android хочет завершить процесс. Это говорит о том, что я не могу позволить этому методу вернуться, пока поток БД не завершит сохранение документа (и на самом деле с моим текущим дизайном я на самом деле не знаю, что такое идентификационный номер документа, пока он не будет сохранен в БД, поэтому я даже не могу поместить это в пакет сохраненного состояния).

Уместно ли в этих обстоятельствах блокировать поток пользовательского интерфейса в ожидании выполнения задачи сохранения? Когда onSaveInstanceState вызывается из-за уничтожения процесса, приложение больше не отображается на переднем плане, поэтому нет интерфейса, который мог бы перестать отвечать на запросы.

Но onSaveInstanceState также вызывается, когда экземпляр Activity уничтожается обновлением конфигурации, что происходит при изменении ориентации экрана. Очень жаль, когда поворот экрана вбок ничего не дает в течение нескольких секунд. В этом случае процесс (и, следовательно, объем памяти) все еще существует, поэтому мне не нужно строго следить за тем, чтобы документ попадал в базу данных, если я могу просто сохранить ссылку на него в Bundle вместо его идентификатора. Но я не знаю, как отличить эти два случая.

Существует ли общепринятая практика для таких ситуаций? Должен ли я просто заблокировать поток, чтобы быть в безопасности? Могу ли я просто использовать обычные примитивы потоков Java для блокировки и ожидания? Есть ли что-то, что я могу сделать, чтобы не блокировать поток, но гарантировать, что задача сохранения будет завершена до того, как Android закроет процесс?

Все это также относится к onPause, так как onSaveInstanceState не обязательно будет вызываться.


person Ben    schedule 19.09.2011    source источник


Ответы (2)


Вам не нужно делать постоянное сохранение в onSaveInstanceState, вы можете просто сохранить состояние экземпляра в Bundle, чтобы экземпляр можно было быстро возобновить в onRestoreInstanceState.

В документации говорится, что вы должны записывать важные постоянные данные (например, пользовательские правки) в хранилище в onPause, но также говорится, что это должно быть быстро, чтобы следующая активность могла начать делать все, что она хочет.

Я думаю, что моя рекомендация здесь заключалась бы в том, чтобы просто сохранить текст документа и все, что находится в Bundle в onSaveInstanceState, и восстановить его в onRestoreInstanceState. Используйте onPause, чтобы быстро сохранить "резервную копию" где-нибудь (может быть, временный файл?), которую затем можно восстановить в onResume, если она не была сохранена в базе данных. И используйте onStop (который вызывается, когда действие уже находится в фоновом режиме), чтобы фактически сохранить данные в базе данных.

Обратите внимание, что активность может быть уничтожена после вызова onPause (никогда раньше, если только в системе не осталось очень-очень мало ресурсов...), поэтому я бы сохранил быструю резервную копию, прежде чем пытаться зафиксировать ее в базе данных.

Редактировать — Дополнительно на основе комментариев

Чтобы убедиться, что фоновый поток, выполняющий процесс сохранения, завершил сохранение до того, как приложение может быть уничтожено системой, я думаю можно заблокировать и дождаться завершения потока сохранения перед возвратом из onPause, но Я рекомендую использовать android:configChanges="orientation" для предотвращения перезапуска активности (и вызова onPause) при изменении ориентации.

person Zharf    schedule 19.09.2011
comment
Я фактически фиксирую все в базе данных, как только она написана. Я не делаю этого в onSaveInstanceState. Проблема в том, что последняя инициированная операция сохранения может продолжаться, когда вызывается onSaveInstanceState. Мне нужно знать, как подождать, чтобы сообщить системе Android, что можно меня убить сейчас, пока постоянные данные не станут действительно безопасными. Если в системе так мало ресурсов, что она в любом случае произвольно завершает мой процесс, можно потерять несохраненные изменения, но я не хочу, чтобы процесс прерывался на полпути операции с БД в нормальных условиях работы. - person Ben; 19.09.2011
comment
В этом случае вы можете пропустить onSaveInstanceState, используя android:configChanges=orientation в файле манифеста, как это было предложено mak_just4anything. Просто убедитесь, что сохранение сделано в onPause/onStop. Дополнительная информация здесь: developer.android.com/guide/topics/ ресурсы/ - person Zharf; 19.09.2011
comment
Я, очевидно, не понимаю мой вопрос. Допустим, мой onPause звонит tellBackgroundThreadToSaveStateToDb. Хорошо. Сделанный. Теперь, как мне убедиться, что фоновый поток не обрабатывает этот запрос, когда Android хочет убить мой процесс? - person Ben; 19.09.2011
comment
Если вы используете AsyncTask или FutureTask, вы можете использовать метод get для блокировки, пока поток не завершит обработку. Если нет, заблокируйте другим способом... - person Zharf; 19.09.2011
comment
Итак, блокировка потока пользовательского интерфейса — это то, что нужно делать в этих обстоятельствах? Круто, я об этом и спрашивал. Не стесняйтесь сделать это ответом, поэтому я могу принять его, если ничего другого не появится. - person Ben; 19.09.2011

Вы должны попробовать AsyncTask, который заблокирует ваш пользовательский интерфейс, но не будет отображать пустой экран, загрузит необходимые элементы xml, а затем получит вызов из асинхронной задачи, в асинхронной задаче сохраните ваш документ в базе данных.

Перейдите по этой ссылке: AyncTask Exmaple

person mayank_droid    schedule 19.09.2011
comment
Я думал, что смысл AsyncTask в том, что он не блокирует поток пользовательского интерфейса? Разве не в этом весь смысл использования его для выполнения длительных операций? - person Ben; 19.09.2011
comment
Если у вас возникли проблемы с изменением конфигурации, не беспокойтесь, просто запишите configChanges в файле mainfest в этом теге активности, чтобы он никогда не вызывал onSaveInstanceState() при изменении ориентации. Это не заставит активность перезапуститься - person mayank_droid; 19.09.2011
comment
Это удобно (но имеет свои проблемы), но совершенно не имеет отношения к вопросу, а именно, как я могу гарантировать, что постоянные данные, которые мы действительно сохраняем, когда приложение убито, если сохранение выполняется фоновым потоком. - person Ben; 19.09.2011