Поскольку все больше разработчиков используют внедрение зависимостей (например, Dagger) в Android и используют такие шаблоны, как MVP или MVVM, эта тема необходима как никогда. В последнее время наблюдается всплеск использования того, что я бы назвал «скрытыми синглетонами», один и тот же антипаттерн, только объединенный по-другому.

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

И здесь кроется проблема, которую некоторые разработчики не осознают полностью - весь процесс был убит. Итак, любые синглтоны (или любые объекты «области действия приложения»), любые временные данные, любые данные, хранящиеся в ваших «сохраненных фрагментах» - все будет в состоянии, как если бы вы только что запустили приложение. С одной большой разницей - состояние восстанавливается, пользователь находится в том месте, где он покинул приложение.

Представьте себе, что в вашей деятельности вы зависите от некоторого общего объекта или некоторой внедренной зависимости, в которой вы храните последние данные. Скорее всего, приложение просто выйдет из строя из-за исключения NullPointerException, потому что вы не ожидали, что данные будут иметь значение NULL.

Как протестировать фоновое уничтожение и восстановление приложения?

  1. Запустите приложение, откройте новое действие, поработайте.
  2. Нажмите кнопку «Домой» (приложение будет в фоновом режиме, в остановленном состоянии).
  3. Завершить работу приложения - самый простой способ - просто нажать красную кнопку «Стоп» в Android Studio.
  4. Вернитесь к своему приложению (запустите из недавних приложений).
  5. Крушение? Вы делаете что-то не так в своем приложении :-).

Открыв приложение - система восстановит свое состояние, и пользователь даже не заметит, что на самом деле процесс за это время был остановлен. Хорошо, если ваше приложение не выйдет из строя из-за того, что вы не были к этому готовы.

Для этого сценария явно недостаточно просто протестировать приложение с помощью параметра «Не сохранять действия» в настройках отладки. Это просто проверит, могут ли ваши действия восстановить свое состояние, но процесс никогда не останавливается таким образом. Сбои начнут приходить, когда вы выпустите свое приложение, пользователи откроют его, оставят в фоновом режиме на день и вернутся обратно.

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

Возмутители спокойствия в вашем приложении

  • Синглтоны
  • Любые другие общие экземпляры, которые хранят изменяемые данные (например, внедренные зависимости, в которых вы сохраняете какое-то состояние).
  • Данные и состояние, хранящиеся в вашем классе приложения
  • Изменяемые статические поля
  • Сохраненные фрагменты (состояние восстановлено, данные потеряны)
  • В основном все, что не хранится в onSaveInstanceState, и вы от него зависите

Единого решения не существует, и это зависит от типа вашего приложения. Как правило, вам следует избегать всего, что упоминается в списке, но это не всегда легко или возможно.

Вы должны иметь возможность «повторно инициализировать» состояние - либо загружать данные из базы данных, SharedPreferences, либо повторно загружать все необходимое.

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

Знайте правила платформы Android

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

И как всегда - протестируйте свое приложение на эти случаи. Эта конкретная проблема плоха в том смысле, что вы почти никогда не увидите ее во время разработки и простого тестирования. Но конечные пользователи будут сталкиваться с этим регулярно.

Следуйте за мной и читайте о возможных решениях этой проблемы в следующей статье.