жизненный цикл андроид приложения

Activity

Activity и жизненный цикл приложения

Жизненный цикл приложения

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

После запуска activity проходит через ряд событий, которые обрабатываются системой и для обработки которых существует ряд обратных вызовов:

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

жизненный цикл андроид приложения

onCreate()

onStart

onResume

При вызове метода onResume activity переходит в состояние Resumed и отображается на экране устройства, и пользователь может с ней взаимодействовать. И собственно activity остается в этом состоянии, пока она не потеряет фокус, например, вследствии переключения на другую activity или просто из-за выключения экрана устройства.

onPause

onStop

В этом методе activity переходит в состояние Stopped. В этом состоянии activity полностью невидима. В методе onStop следует особождать используемые ресурсы, которые не нужны пользователю, когда он не взаимодействует с activity. Здесь также можно сохранять данные, например, в базу данных.

При этом во время состояния Stopped activity остается в памяти устройства, сохраняется состояние всех элементов интерфейса. К примеру, если в текстовое поле EditText был введен какой-то текст, то после возобновления работы activity и перехода ее в состояние Resumed мы вновь увидим в текстовом поле ранее введенный текст.

onDestroy

В целом переход между состояниями activity можно выразить следующей схемой:

жизненный цикл андроид приложения

Управление жизненным циклом

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

И при запуске приложения мы сможем увидеть в окне Logcat отладочную информацию, которая определяется в методах жизненного цикла activity:

Источник

Жизненный цикл Android-приложений

Авторизуйтесь

Жизненный цикл Android-приложений

жизненный цикл андроид приложения

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

Чтобы обеспечить такой UX, вам следует знать, как управлять жизненными циклами компонентов, таких как активности, фрагменты, сервисы, приложение в целом и так далее. Во время работы компонент проходит через состояния, определяемые его жизненным циклом. Система уведомляет о таких переходах через методы обратного вызова (callbacks).

Обратите внимание: Диаграммы описывают поведение в Android P / Jetpack 1.0.

Диаграммы показывают сценарии поведения по умолчанию, если не указано иное.

Жизненный цикл одной активности

Сценарий 1: завершение и повторный запуск приложения

Источники

Этот простейший сценарий показывает, что происходит, когда приложение с одной активностью завершается и снова запускается пользователем:

жизненный цикл андроид приложения

Сценарий 1: приложение завершено и перезапущено

Управление состоянием

Сценарий 2: переход пользователя из приложения

Источники

жизненный цикл андроид приложения

Сценарий 2: пользователь покидает приложение

В этом случае система остановит активность, но не будет сразу же завершать её.

Управление состоянием

Когда активность входит в остановленное состояние, система вызывает onSaveInstanceState() для сохранения состояния приложения на случай, если она завершит процесс впоследствии.

4–5 декабря, Онлайн, Беcплатно

Предполагая, что процесс всё же не будет завершён, активность вместе со своим состоянием остаётся резидентной в памяти. Когда активность возвращается на передний план, её состояние доступно целиком и нет необходимости в повторной инициализации ранее созданных компонентов.

Сценарий 3: изменение конфигурации

Источники

жизненный цикл андроид приложения

Сценарий 3: поворот и другие изменения конфигурации

Управление состоянием

Изменения конфигурации вроде поворота и увеличения или уменьшения окна, должны позволять пользователям продолжать работу именно там, где они остановились:

Сценарий 4: остановка приложения системой

Источники

жизненный цикл андроид приложения

Сценарий 4 — остановка приложения системой

Сценарий не относится к следующим случаям:

Навигация и стек переходов

Примечание Показанные друг напротив друга группы событий отрабатываются параллельно. Поток выполнения может переключиться с одной группы событий на другую в любой момент времени, поэтому порядок вызовов методов из параллельных групп не определён. Однако последовательный порядок вызовов методов внутри группы гарантирован. Следующие сценарии не применяются к активностям и задачам с кастомным режимом запуска или заданным контекстом задачи (task affinity). За более подробной информацией обратитесь к документации на Android Developers.

Сценарий 1: навигация между активностями

жизненный цикл андроид приложения

Cценарий 1: завершение и повторный запуск приложения

В этом сценарии при старте новой активности первая останавливается (но не разрушается), что похоже на переход пользователя из приложения (по кнопке «Home»).

После нажатия на кнопку «Back» вторая активность разрушается и завершается.

Управление состоянием

Заметьте, что onSaveInstanceState() вызывается, а onRestoreInstanceState() — нет. Если изменение конфигурации произойдёт в то время, когда вторая активность открыта, то первая разрушится и будет снова создана, когда получит фокус обратно. Вот почему сохранение состояния важно.

Если система убьёт процесс для освобождения ресурсов, будет иметь место другой сценарий, в котором состояние потребуется восстановить.

Сценарий 2: активности в стеке переходов и изменения конфигурации

жизненный цикл андроид приложения

Сценарий 2: активности в стеке переходов и изменения конфигурации

Управление состоянием

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

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

Завершение процесса

Когда Android нуждается в ресурсах, он завершает фоновые приложения.

жизненный цикл андроид приложения

Сценарий 3: завершение процесса

Управление состоянием

Несмотря на то, что весь стек переходов сохраняется, в целях эффективного использования ресурсов системы активности восстанавливаются только тогда, когда они заново создаются.

Узнать больше можно здесь.

Жизненный цикл фрагментов

В этой части обсудим поведение прикреплённых к активности фрагментов. Не смущайтесь сценария с добавлением фрагмента в стек переходов назад (подробнее о транзакциях фрагментов и стеке переходов здесь).

Сценарий 1: запуск активности с фрагментом и её завершение

жизненный цикл андроид приложения

Сценарий 1: запуск активности с фрагментом и её завершение

Примечание Будьте осторожны при управлении потоками выполнения и избегайте состояния гонки.

Сценарий 2: поворот активности с фрагментом

жизненный цикл андроид приложения

Сценарий 2: поворот действия с фрагментом

Управление состоянием

Фрагменты могут быть сохранены, то есть при изменении конфигурации активности будет использоваться один и тот же экземпляр фрагмента.

Сценарий 3: поворот активности с сохранённым фрагментом

жизненный цикл андроид приложения

Сценарий 3: поворот активности с сохранённым фрагментом

После поворота фрагмент не разрушается и не воссоздаётся, потому что после пересоздания активности используется тот же экземпляр фрагмента — при этом в onActivityCreated() всё ещё доступен объект состояния.

Не рекомендуется применять сохраняемые фрагменты, если они не используются для сохранения данных между изменениями конфигурации (в не UI-фрагменте). Класс ViewModel из библиотеки Architecture Components внутри реализован именно так, но он предоставляет более простой API.

ViewModels, полупрозрачные активности и режимы запуска

Модели представления (ViewModels)

жизненный цикл андроид приложения

Различие между активностью и фрагментом

Полупрозрачные активности

Из названия понятно, что у полупрозрачной активности полупрозрачный фон (как правило, совсем прозрачный). Таким образом, пользователь видит, что находится под ней.

жизненный цикл андроид приложения

Сравнение обычной и полупрозрачной активностей

Также при возвращении обратно к задаче, обе активности восстанавливаются и запускаются, и только полупрозрачная возобновляется:

жизненный цикл андроид приложения

Новая полупрозрачная активность: выход из приложения и повторное открытие

Режимы запуска

Рекомендованный способ работы с задачами и стеками переходов в своей основе прост — вы должны следовать поведению по умолчанию. За подробной информацией обратитесь к статье.

жизненный цикл андроид приложения

Для сравнения посмотрите на следующей диаграмме режим singleTask (но, скорее всего, вам не нужно его использовать):

жизненный цикл андроид приложения

Если вы используете Navigation Architecture из Jetpack, то получите выгоду от поддержки Single Top и автоматического искусственного стека переходов.

Источник

Жизненный цикл приложения на Android

жизненный цикл андроид приложения

Жизненный цикл приложения в Android жёстко контролируется системой и зависит от нужд пользователя, доступных ресурсов и т. д. Например, пользователь хочет запустить браузер. Решение о запуске приложения принимает система. Хотя последнее слово и остаётся за системой, она подчиняется определённым заданным и логическим правилам, позволяющим определить, можно ли загрузить, приостановить приложение или прекратить его работу. Если в данный момент пользователь работает с определённым окном, система даёт приоритет соответствующему приложению. И наоборот, если окно невидимо и система решает, что работу приложения необходимо остановить, чтобы мобилизовать дополнительные ресурсы, будет прекращена работа приложения, имеющего более низкий приоритет. В Android ресурсы более ограниченны, поэтому Android более жёстко контролирует работу приложений.

Основные методы жизненного цикла приложения

У методов onCreate(), onStart(), onResume() вызов суперкласса должен происходить до вызова вашего кода. В методах onPause(), onStop(), onDestroy() суперкласс следует вызывать после вашего кода (не обращайте внимания на мои примеры).

onCreate()

Метод onCreate() вызывается при создании или перезапуска активности. Система может запускать и останавливать текущие окна в зависимости от происходящих событий. Внутри данного метода настраивают статический интерфейс активности. Инициализирует статические данные активности, связывают данные со списками и т.д. Связывает с необходимыми данными и ресурсами. Задаёт внешний вид через метод setContentView().

В этом методе загружайте пользовательский интерфейс, размещайте ссылки на свойства класса, связывайте данные с элементами управления, создавайте сервисы и потоки. Метод onCreate() принимает объект Bundle, содержащий состояние пользовательского интерфейса, сохранённое в последнем вызове обработчика onSaveInstanceState. Для восстановления графического интерфейса в его предыдущем состоянии нужно задействовать эту переменную: внутри onCreate() или переопределив метод onRestoreInstanceState().

Операции по инициализации, занимающие много времени, следует выполнять в фоновом процессе, а не с помощью метода onCreate(). В противном случае можно получить диалоговое окно ANR (Application Not Responding, приложение не отвечает).

В методе можно сделать проверку, запущено ли приложение впервые или восстановлено из памяти. Если значение переменной savedInstanceState будет null, приложение запускается первый раз:

А значение переменной currentBillTotal можно сохранить в методе onSaveInstanceState():

onStart()

За onCreate() всегда следует вызов onStart(), но перед onStart() не обязательно должен идти onCreate(), так как onStart() может вызываться и для возобновления работы приостановленного приложения (приложение останавливается методом onStop()). При вызове onStart() окно ещё не видно пользователю, но вскоре будет видно. Вызывается непосредственно перед тем, как активность становится видимой пользователю. Сопровождается вызовом метода onResume(), если активность получает передний план, или вызовом метода onStop(), если становится скрытой.

onResume()

Метод onResume() вызывается после onStart(), даже когда окно работает в приоритетном режиме и пользователь может его наблюдать. В этот момент пользователь взаимодействует с созданным вами окном. Приложение получает монопольные ресурсы. Запускает воспроизведение анимации, аудио и видео. Также может вызываться после onPause().

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

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

Вам не нужно перезагружать состояние пользовательского интерфейса внутри него, так как эти функции возложены на обработчики onCreate() и onRestoreInstanceState.

Например, после метода onPause(), в котором мы приостановили работу камеры (см. ниже) снова запускаем камеру:

onPause()

Когда пользователь решает перейти к работе с новым окном, система вызовет для прерываемого окна метод onPause(). По сути происходит свёртывание активности. Сохраняет незафиксированные данные. Деактивирует и выпускает монопольные ресурсы. Останавливает воспроизведение видео, аудио и анимацию. От onPause() можно перейти к вызову либо onResume(), либо onStop().

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

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

Исходя из архитектуры своего приложения, вы также можете приостановить выполнение потоков, процессов или широковещательных приёмников, пока активность не появится на переднем плане.

Например, при работе с камерой метод используется следующим образом:

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

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

onStop()

Метод onStop() вызывается, когда окно становится невидимым для пользователя. Это может произойти при её уничтожении, или если была запущена другая активность (существующая или новая), перекрывшая окно текущей активности. Всегда сопровождает любой вызов метода onRestart(), если активность возвращается, чтобы взаимодействовать с пользователем, или метода onDestroy(), если эта активность уничтожается.

Когда ваша активность останавливается, объекты активности хранятся в памяти и восстанавливаются, когда активность возобновляет свою работу. Вам не нужно повторно инициализировать компоненты, которые были созданы ранее. Кроме того, система отслеживает текущее состояние для каждого представления, поэтому, если пользователь введёт текст в текстовое поле, то его содержание сохраняется и вам не нужно сохранять и восстанавливать его.

Примечание: Даже если система закрыла вашу активность, когда она была остановлена, она по-прежнему сохраняет состояние объектов, таких как текст в EditText в специальном объекте Bundle (в виде ключ-значение) и восстанавливает их, если пользователь переходит обратно к тому же экземпляру активности.

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

При нехватке памяти система может уничтожить скрытую активность, минуя метод onStop() с вызовом метода onDestroy().

onRestart()

Если окно возвращается в приоритетный режим после вызова onStop(), то в этом случае вызывается метод onRestart(). Т.е. вызывается после того, как активность была остановлена и снова была запущена пользователем. Всегда сопровождается вызовом метода onStart().

onRestart предшествует вызовам метода onStart() (кроме самого первого). Используйте его для специальных действий, которые должны выполняться только при повторном запуске активности в рамках «полноценного» состояния.

onDestroy()

Метод вызывается по окончании работы активности, при вызове метода finish() или в случае, когда система уничтожает этот экземпляр активности для освобождения ресурсов. Эти два сценария уничтожения можно определить вызовом метода isFinishing(). Вызывается перед уничтожением активности. Это последний запрос, который получает активность от системы. Если определённое окно находится в верхней позиции в стеке, но невидимо пользователю и система решает завершить это окно, вызывается метод onDestroy(). В этом случае метод удаляет все статические данные активности. Отдаёт все используемые ресурсы.

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

На практике вам чаще всего придется сталкиваться с методами onCreate(), onResume() и onPause(). Метод onCreate() будет вызываться при создании пользовательского интерфейса для работы с окном. Данный метод позволит вам связывать данные с компонентами и подключать обработчики событий к компонентам пользовательского интерфейса. При помощи onPause() вы сможете сохранить важную информацию в базе данных вашего приложения. Это последний безопасный метод, который будет вызываться перед тем, как система завершит работу приложения. Метод onDestroy() не обязательно будет вызываться, поэтому не полагайтесь на этот метод при реализации критическом логики.

Пример

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

Запускайте проект и следите за сообщениями. Они будут всплывать в нужной последовательности, давая вам представление о жизненном цикле приложения. Также сообщения будут транслироваться в окно logcat на вкладке 6.Android в студии. Обратите внимание на следующий момент. Когда ваше приложение запущено, то нажмите на первую кнопку, чтобы изменить текст в TextView. Затем нажмите кнопку «Home» (не Back!), чтобы попасть на Домашний экран. После чего снова запустите ваше приложение. Вы увидите, что приложение не вызывает метод onCreate(), а текст в TextView будет свидетельствовать, что приложение не было закрыто, а только свёрнуто. Это очень важный момент, который нужно понять. Понимание этих вещей поможет вам правильно выстраивать логику приложения.

Памятка

Нажимаем кнопку Назад для выхода из приложения

Нажата кнопка Домой

После нажатия кнопки Домой, когда приложение запущено из списка недавно открытых приложений или через значок

Когда запускается другое приложение из области уведомлений или открывается приложение Настройки

Нажата кнопка Назад в другом приложении или в Настройках и ваше приложение стало снова видимым.

Открывается диалоговое окно

Диалоговое окно закрывается

Кто-то звонит на телефон

Пользователь отвечает на звонок

Экран телефона гаснет

Экран снова включён

На китайских планшетах иногда наблюдал, когда какие-то методы не срабатывали.

При повороте активность проходит через цепочку различных состояний. Порядок следующий.

onPause()
onStop()
onDestroy()
onCreate()
onStart()
onResume()

Порядок вызовов

Источник

Android, жизненый цикл Jetpack компонентов

Руководство по работе с жизненным циклом Android компонентов, рассмотрим базовые понятия, что такое LifecycleObserver, события и состояния жизненного цикла, кастомные LifecycleOwner.

используется: Kotlin 1.4, Android 10.0, Android Studio 4.2.

В этой статье, вы создадите компонент, учитывающий жизненный цикл (lifecycle-aware компонент), в приложении AwarenessFood. Компонент будет обрабатывать изменения сетевого подключения. Вы также создадите lifecycle owner для обновления состояние сети в Activity.

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

В статье вы изучите:

Жизненные циклы в Android компонентах

Компоненты учитывающие жизненный цикл (Lifecycle-aware components)

Наблюдателей жизненного цикла (Lifecycle observers)

События и состояния

Владельцев жизненного цикла (Lifecycle owners)

Как тестировать Lifecycle-aware компоненты

Статья предполагает, что вы знакомы с основами разработки под Android. Если это не так, посмотрите руководство для начинающих в Android.

Начало

Загрузите материал с оригинальной статьи (кнопка Download вверху страницы здесь). Откройте Android Studio версии 4.2.1 или выше и импортируйте проект.

Ниже общая информация, что делает каждый пакет в проекте:

analytics классы для трекинга событий в приложении

data классы модели

di поддержка зависимостей

monitor содержит единственный класс, который смотрит за состоянием подключения к сети

network классы для доступа к внешним API

repositories классы для доступа к постоянному хранилищу

viewmodels бизнес логика

view экраны

Регистрация в spoonacular API

AwarenessFood приложение получает рецепты через spoonacular API. Вам нужно зарегистрироваться там, чтобы приложение работало правильно.

Заходим на сайт spoonacular.com и создаем новый аккаунт. После подтверждения аккаунта, входим в личный кабинет и ищем там API ключ. Копируем его, открываем файл RecipesModule.kt внутри пакета di и заменяем ключ в следующей строке:

Компилируем и запускаем. Должен появиться экран со случайным рецептом, похожий на такой:

жизненный цикл андроид приложения

Жмем на кнопку Reload, чтобы загрузить другой случайный рецепт. Если отключить интернет на устройстве и попробовать получить новый рецепт, то появится SnackBar с ошибкой и кнопкой повторить, как на изображении ниже:

жизненный цикл андроид приложения

Чтобы перейти на экран деталей, жмем в меню More пункт Food Trivia. Вы добавите этот функционал позже. Сейчас это просто экран с кнопкой:

жизненный цикл андроид приложения

На этом настройка проекта закончена. Сейчас вы готовы познакомиться с компонентами, учитывающие жизненный цикл (lifecycle-aware).

Жизненные циклы в Android

Жизненный цикл Activity:

жизненный цикл андроид приложения

Для тех, кто хочет узнать побольше о жизненном цикле Activity, взгляните на статью Introduction to Android Activities With Kotlin.

Жизненный цикл Fragment:

жизненный цикл андроид приложения

Реагируем на изменения жизненного цикла

При таком подходе, ваш код может стать запутанным и подверженным ошибкам. Код внутри методов onStart() и onStop() будет нарастать бесконечно. При этом, легко забыть отписаться от компонента или вызвать метод компонента в неподходящем событии жизненного цикла, что может привести к багам, утечкам памяти и падениям приложения.

Некоторые из этих проблем есть прямо сейчас в приложении. Откройте файл NetworkMonitor.kt в проекте. Этот класс слушает состояние сети и уведомляет Activity об этом.

В MainActivity используется только один компонент, который зависит от жизненного цикла Activity. В более крупных и сложных проектах таких компонентов гораздо больше и это может привести к полному беспорядку.

Используем компоненты жизненного цикла (Lifecycle-Aware)

Владелец жизненного цикла (lifecycle owner) – это компонент имеющий жизненный цикл, такой как Activity или Fragment. Владелец жизненного цикла должен знать все компоненты, которые будут слушать события жизненного цикла. Паттерн «Наблюдатель» считается лучшим подходом для решения такой задачи.

Создание наблюдателя жизненного цикла (lifecycle observer)

Вот и все, теперь это lifecycle наблюдатель. Вы только что сделали первый шаг по превращению NetworkMonitor в lifecycle-aware компонент.

События и состояния жизненного цикла

Lifecycle использует два перечисления для обмена данными о жизненном цикле: Event и State.

Events

Event представляет события жизненного цикла, которые отправляет операционная система:

Каждое значение это эквивалент колбека жизненного цикла. ON_ANY отличается тем, что отправляется при каждом событии (можно сделать один метод для обработки всех событий).

Реакция на события жизненного цикла

Сейчас NetworkMonitor – это LifecycleObserver, но он пока не реагирует на жизненный цикл. Нужно добавить аннотацию @OnLifecycleEvent к методу, чтобы он начал реагировать на конкретное событие.

Добавьте @OnLifecycleEvent к нужным методам, как указано ниже:

Итак, NetworkMonitor теперь получает изменения жизненного цикла, сейчас нужно немного подчистить код. Следующий код больше не нужен в MainActivity.kt, потому что эти действия NetworkMonitor выполняет сам:

Сделав эти изменения в коде, вы переместили из Activity ответственность за инициализацию, регистрацию и освобождение ресурсов в сам компонент.

Состояния (States)

State хранит текущее состояние владельца жизненного цикла. Возможные значения:

Состояния жизненного цикла сигнализируют, что конкретное событие случилось.

Есть прямая связь между событиями и состояниями жизненного цикла. На диаграмме ниже, показана это взаимосвязь:

жизненный цикл андроид приложения

Эти состояния возникают при:

INITIALIZED: Когда Activity или Fragment уже созданы, но onCreate() еще не вызван. Это первоначальное состояние жизненного цикла.

Используем состояния (State) жизненного цикла

Иногда компоненты должны выполнять код, если их родитель находится, по крайней мере, в определенном состоянии. Нужно быть уверенным, что NetworkMonitor выполняет registerNetworkCallback() в нужный момент жизненного цикла.

Добавьте Lifecycle аргумент в конструктор NetworkMonitor :

С ним у NetworkMonitor будет доступ к состоянию жизненного цикла родителя.

После этого добавьте в код registerNetworkCallback() условие:

Итак, откройте MainActivity.kt и сделайте изменения для NetworkMonitor :

У NetworkMonitor сейчас есть доступ к родительскому жизненному циклу и прослушивание сети запускается только когда Activity находится в нужном состоянии.

Подписка на события жизненного цикла

Чтобы NetworkMonitor действительно начал реагировать на изменения, его родитель должен зарегистрировать NetworkMonitor как слушателя событий. В MainActivity.kt добавьте следующую линию в методе onCreate() после инициализации компонента:

Теперь владелец жизненного цикла будет уведомлять NetworkMonitor об изменениях. Таким же образом можно добавить другие компоненты на прослушивание событий жизненного цикла.

Это отличное улучшение. С помощью одной строчки кода компонент будет получать события жизненного цикла от родителя. Больше не надо писать шаблонный код в Activity или Fragment. Кроме того, компонент содержит весь код инициализации и конфигурации, что делает его самодостаточном и тестируемым.

Соберите и запустите приложение снова. После загрузки рецептов включите «Самолетный режим». Вы увидите ошибку сети в SnackBar, так же как и раньше:

жизненный цикл андроид приложения

Однако внутреннняя реализация была значительно улучшена.

Кто владеет жизненным циклом?

Все выглядит хорошо, но. кто владеет жизненным циклом? Почему Activity сама владеет жизненным циклом в этом примере? Существуют ли другие владельцы?

Android имеет встроенные компоненты с поддержкой жизненного цикла. Для Activity это ComponentActivity (является базовым классом для AppCompatActivity и реализует интерфейс LifecycleOwner ).

Жизненный цикл Fragment может быть значительно длиннее, чем цикл визуальных компонентов (UI), которых он содержит. Если наблюдатель взаимодействует с UI во Fragment, это может привести к проблемам, поскольку наблюдатель может изменить UI до инициализации или после уничтожения.

Используя этот код, FoodTriviaFragment будет реагировать на события от foodTriviaState (является LiveData ). Так как Fragment является владельцем жизненного цикла ( viewLifecycleOwner ), наблюдатель будет получать обновления данных только, когда Fragment находится в активном состоянии.

Время сделать сборку и запустить приложение. Нажмите More в меню и выберите Food Trivia. Теперь можно получить несколько забавных и интересных Food Trivia в вашем приложении.

жизненный цикл андроид приложения

Использование ProcessLifecycleOwner

Этот класс представляет жизненный цикл всего процесса приложения. Событие ON_CREATE посылается только один раз, когда приложение стартует. При этом событие ON_DESTROY не будет посылаться вообще.

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

Регистрация такого LifecycleObserver происходит немного по-другому. Откройте RecipesApplication.kt и добавьте следующий код в метод onCreate() :

Здесь мы получаем экземпляр ProcessLifecycleOwner и добавляем appGlobalEvents как слушателя событий.

Соберите и запустите приложение. После старта приложения, сверните его в фон. Если открыть LogCat и отфильтровать вывод по тегу APP_LOGGER, то вы должны увидеть сообщения:

жизненный цикл андроид приложения

Создаем собственного владельца жизненного цикла

Давайте создадим такого владельца, жизненный цикл которого начинается, когда смартфон теряет сетевое соединение и заканчивается при восстановлении соединения.

Откройте UnavailableConnectionLifecycleOwner.kt в пакете monitor и сделайте изменения, чтобы класс поддерживал интерфейс LifecycleOwner :

После этого, добавьте LifecycleRegistry в UnavailableConnectionLifecycleOwner:

Добавляем события

Наконец, добавьте следующий код:

Реакция на события

Теперь откройте MainActivity.kt и добавьте такую строчку кода:

И наконец, замените handleNetworkState() :

Время собрать и запустить ваше приложение. Все работает так же как и раньше, кроме мониторинга сети, где мы используем сейчас кастомный lifecycleOwner для обработки сетевого состояния.

В следующей секции, вы узнаете как тестировать компоненты жизненного цикла.

Тестирование компонентов жизненного цикла

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

Настройка тестов

Здесь используется функционал библиотеки MockK<:target="_blank">, она позволяет имитировать реализацию класса. Аргумент relaxed говорит, что заглушки могут работать без указания их поведения.

После этого создайте переменную:

Этот код добавляет объект LifecycleRegistry в тест, для управления наблюдателями и рассылки им событий жизненного цикла.

И наконец, добавьте следующую строчку кода в метод setup() :

Добавляем тесты

Давайте напишем тест:

Сначала устанавливаете состояние ON_CREATE

Не забудьте импортировать зависимости:

Запускайте тест, он проходит успешно.

Этот код проверяет ON_START событие.

Тест должен пройти успешно.

В конце концов, создадим тест для проверки события ON_STOP и вызова метода unregisterNetworkCallback() :

Этот код проверяет ON_STOP событие.

Добавляем событие ON_START в тест:

Теперь тест проходит успешно.

LiveData: компонент жизненного цикла

К этому моменту вы узнали, как создавать собственный компонент жизненного цикла. Но существуют ли такие же готовые компоненты в Android? Конечно, возможно самый известный из них это LiveData.

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

Создание и присваивание переменных LiveData

Откройте MainViewModel.kt из пакета viewmodels. Добавьте там следующие переменные:

Каждый раз, когда LiveData переменная получает новое значение, она уведомляет своих слушателей об изменении. Для установки нового значения используйте поле value.

Давайте изменим метод getRandomRecipe() :

Наблюдения за изменениями LiveData

Откройте MainActivity.kt и добавьте код в метод onCreate() :

В методе observe() есть такой код:

Видно, если LifecycleOwner в состоянии DESTROYED и новое значение было установлено для переменной, то наблюдатель не получит обновление.

Однако, если LifecycleOwner становится активным опять, то наблюдатели получат последнее значение автоматически.

Соберите и запустите проект. Приложение будет показывать прогресс бар во время загрузки приложения, после окончания прогресс бар скрывается.

Поздравляю! Вы отрефакторили проект с использованием компонентов жизненного цикла.

Что посмотреть?

Официальная документация по архитектурным компонентам: Architecture Components: Official Documentation.

Дополнительные материалы по тестированию Jetpack компонентов: Testing Android Architecture Components.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *