Как Android обрабатывает фоновые потоки при выходе из Activity?
Мне нужно мое приложение для Android, чтобы сохранить его на диске, когда его активность будет помещена в фоновом режиме или убита. Было предложено начать поток, когда вызывается onPause() и выполняются какие-либо дорогостоящие процедуры ввода-вывода (см. Сохранение/загрузка документа быстро и надежно для редактора изображений).
В каких ситуациях ОС будет убивать поток и как обычно происходят эти ситуации?
Я предполагаю, что это будет похоже на то, как решаются действия, когда ОС может произвольно решить убить поток, но в основном будет делать это только тогда, когда ресурсы крайне ограничены. Было бы неплохо найти определенную документацию об этом, хотя.
От игры с некоторым тестовым кодом фоновый поток, запущенный в onPause(), будет работать бесконечно в фоновом режиме на моем устройстве (я пытался загружать множество приложений и не мог заставить его быть убитым).
Для моего конкретного приложения я пишу редактор растровых изображений, в котором я использую шаблон Command и шаблон Memento, чтобы разрешить отмену и повтор изменений. Я хотел бы, чтобы пользователь мог отменить/изменить свои правки, например, пользователь получает телефонный звонок, и активность убивается, когда он помещается в фоновом режиме. Лучшее решение, которое я могу придумать, - использовать фоновый поток для постоянного сохранения моих команд и объектов памяти на диске во время использования приложения и для завершения сохранения любых объектов, оставшихся в фоновом потоке, если вызывается onPause. В худшем случае, если поток убит, я только потеряю некоторые изменения.
Ответы
Ответ 1
В каких ситуациях ОС будет убивать поток и как обычно происходят эти ситуации?
ОС не будет убивать поток, если только это не убивает процесс. Android не делает ничего с потоками, которые вы создаете сами. Если вы являетесь процессом переднего плана, вы не будете убиты. Шансы Android, убивающие процесс в течение нескольких секунд после проигрыша переднего плана (после onPause()
), незначительны. Документацию о времени жизни процесса - что есть в ней - можно найти здесь.
Ответ 2
Ваша нить может быть убита в любое время после того, как действие будет уничтожено или оно никогда не будет убито. В зависимости от такой нити очень плохая форма - вы можете закончить с полузаполненной операцией или с нитью, которая торчит навсегда.
Если вы хотите выполнить фоновый режим, который продолжается, даже если нет активности переднего плана, вы почти всегда хотите запустить его внутри Сервиса. С другой стороны, услуга с меньшей вероятностью будет убита, но нет гарантии, если вы не используете "startForeground". Это приведет к появлению уведомления пользователя о том, что что-то происходит в фоновом режиме, но насколько я знаю, это единственный способ запустить асинхронный фоновый поток, который гарантированно не будет убит.
Честно говоря, правильный ответ заключается в том, чтобы убедиться, что никогда не существует какого-либо временного состояния процесса, которое потребуется много времени для сохранения. Если вам нужно написать большой файл, чтобы отразить несколько пользовательских изменений, подумайте о том, чтобы сохранить "журнал транзакций", который вы можете использовать для создания перезапускаемой операции сохранения. Учитывая это, вы можете безопасно запускать свои сейвы в службе и знать, что даже если он будет убит, он будет автоматически перезагружен, когда ресурсы станут доступными.
Ответ 3
Как правило, сохранение состояния в onPause
- это правильная вещь, если это быстро. Я не думаю, что это четко задокументировано, когда процесс убит, но иногда вы видите его в logcat, когда вы запускаете некоторые требовательные приложения (скажем, после запуска Google Earth и браузера).
В Android DevTools также есть возможность автоматически уничтожать действия при удалении от них, хотя это, вероятно, не распространяется на процесс. (DevTools находятся в эмуляторе и на некоторых корневых телефонах).
Я думаю, что ваш подход звучит разумно - используйте поток с низким приоритетом, чтобы постоянно обновлять данные сохранения и придать ему нормальный приоритет в onPause и установить флаг в onPause, который сообщает ему прекратить работу после завершения.
Очевидно, что вам нужно убедиться, что вы не запускаете проблемы синхронизации, если вы получаете onResume сразу после onPause (т.е. пока поток по-прежнему занят сохранением).