- Остановка и перезапуск Activity
- В этом уроке
- Вы также должны прочитать
- Попробуйте
- Остановка вашей activity
- Как перезапустить активность Android
- 18 ответов
- Перезагрузить активность в Android
- 14 ответов
- Как перезапустить Android-активность
- Жизненный цикл Android
- Жизненный цикл Android
- Начнем
- Понимание роли жизненного цикла приложений
- Изучение жизненного цикла активности
- Заметка
- Понимание колбэков жизненного цикла активити
- Заметка
- Сохранение и восстановление состояния экземпляра активити
- Сохранение состояния экземпляра
- Заметка
- Восстановление состояния
- Заметка
- Заметка
- Передача данных между экранами
- Разбираем данные объекта Intent
- Изучение жизненного цикла фрагмента
- Понимание обратных вызовов жизненного цикла фрагмента
- Использование ViewModel для хранения данных пользовательского интерфейса
Остановка и перезапуск Activity
В этом уроке
Вы также должны прочитать
Попробуйте
Правильная остановка и перезапуск вашей activity является важным процессом жизненного цикла activity , который дает пользователям чувство, что ваше приложение всегда живое и не теряет их прогресс. Есть несколько ключевых сценариев, в которых ваша activity останавливается и перезапускается:
- Пользователь открывает окно Недавние приложения и переключается с вашего приложения на другое приложение. activity вашего приложения, находящаяся в это время на переднем плане, останавливается. Если пользователь возвращается в ваше приложении с помощью значка запуска главного экрана или окна Недавние приложения, activity перезагружается.
- Пользователь выполняет действие в вашем приложении, которое начинается новую activity . Текущая activity будет остановлена, когда вторая activity будет создана. Если пользователь затем нажимает кнопку Назад , первая activity перезапустится.
- Пользователь получает телефонный звонок во время использования приложения на его или ее телефоне.
Activity класс предоставляет два метода жизненного цикла, onStop() и onRestart() , которые позволяют специально обрабатывать то, как ваша activity будет останавливаться и перезапускаться. В отличие от состояния приостановки, которое означает частичное перекрытие элементов пользовательского интерфейса, состояние остановки vгарантирует, что пользовательский интерфейс больше не виден и фокус пользователя находится в другой activity (или совершенно другом приложении).
Примечание: Поскольку система удерживает ваш Activity экземпляр в системной памяти, когда он остановлен, вполне возможно, что вам не нужно реализовывать onStop() и onRestart() (или даже onStart() методы вообще. Для большинства activity , которые относительно простые, activity будет остановлена и перезапущена вполне нормально, и вы, возможно, должны использовать только onPause() для приостановки текущих действий и отсоединения от системных ресурсов.
Рисунок 1. Когда пользователь покидает вашу activity , система вызывает onStop() для прекращения activity (1). Если пользователь возвращается по время остановки activity , система вызывает onRestart() (2), а затем быстро onStart() (3) и onResume() (4). Обратите внимание, что независимо от того, какой сценарий вызывает остановку activity , система всегда вызывает onPause() перед вызовом onStop() .
Остановка вашей activity
Когда ваша activity получает вызов onStop() метода, уже ничего не видно и вы должны освободить почти все ресурсы, которые не нужны, пока пользователь их не использует. После того, как ваша activity прекращается, система может уничтожить экземпляр, если это необходимо для восстановления системной памяти. В крайних случаях, система может просто убить ваш процесс приложения без вызова финального onDestroy() метода обратного вызова, поэтому очень важно использовать onStop() для освобождения ресурсов, которые могли бы привести к утечке памяти.
Несмотря на то, что onPause() метод вызывается до onStop() , вы должны использовать onStop() для выполнения более крупных и ресурсоемких операций завершения, таких как запись информации в базу данных.
Например, вот реализация onStop() , который сохраняет содержимое черновика записки в постоянное хранилище:
Источник
Как перезапустить активность Android
Как перезагрузить Android Activity ? Я попробовал следующее, но Activity просто уходит.
18 ответов
Я сделал свой видеомикшер следующим образом:
В принципе, я звоню finish() во-первых, и я использую то же самое намерение, с которого была начата эта деятельность. Это похоже на трюк?
ОБНОВЛЕНИЕ: Как было указано Ральфом ниже, Activity.recreate() — это путь в API 11 и далее. Это предпочтительнее, если вы находитесь в среде API11+. Вы по-прежнему можете проверить текущую версию и вызвать фрагмент кода выше, если вы используете API 10 или ниже. (Пожалуйста, не забудьте упрекнуть Ральфа!)
Начиная с уровня API 11 (Honeycomb), вы можете вызвать recreate() метод активности (благодаря этот ответ.)
Метод recreate() действует так же, как изменение конфигурации, поэтому также вызывают методы onSaveInstanceState() и onRestoreInstanceState().
Перед SDK 11 способ сделать это выглядит так:
Просто, чтобы совместить ответы Ральфа и Бена (включая изменения, сделанные в комментариях):
Это решение сработало для меня.
Сначала завершите действие, а затем запустите его снова.
Я использовал этот код, чтобы поддерживать старые версии Android и использовать recreate() для новых версий Android.
Вызвать этот метод
Это самый простой способ перезапустить текущую активность:
Даже если на это ответили несколько раз.
Если перезагрузка активности из фрагмента, я бы сделал это следующим образом:
Значит, вы думаете, что это немного переборщило? Но проводка Handler позволяет вам вызвать это в методе жизненного цикла. Я использовал это в методах onRestart / onResume при проверке, изменилось ли состояние между пользователем, возвращающимся в приложение. (установлено что-то).
Без Handler , если вы вызываете его в нечетном месте, он просто убьет действие и не перезапустит его.
Не стесняйтесь задавать любые вопросы.
Ну, это не список, а комбо некоторых, которые уже отправлены:
В сочетании с странным поведением SurfaceView жизненного цикла с камерой. Я обнаружил, что recreate() не очень хорошо работает с жизненным циклом SurfaceViews. surfaceDestroyed никогда не называется во время цикла отдыха. Он вызывается после onResume (странный), после чего мой SurfaceView уничтожается.
Исходный способ воссоздания действия отлично работает.
Я не могу точно понять, почему это так, но это просто наблюдение, которое, как мы надеемся, будет направлять других в будущем, потому что оно исправило мои проблемы с SurfaceViews
Существует один хакерский способ, который должен работать над любой деятельностью, включая основную.
При изменении ориентации Android обычно воссоздает вашу активность (если вы не отмените ее). Этот метод полезен для поворотов на 180 градусов, когда Android не воссоздает вашу активность.
попробуйте использовать это.
Фактически для уровней API 5 и выше действует следующий код, поэтому, если ваш целевой API ниже этого, вы получите нечто очень похожее на код EboMike.
Решение для вашего вопроса:
Вам нужно включить в контекст активности, чтобы начать новую деятельность, а также завершить текущую деятельность.
Надеюсь, что это поможет. и работает для меня.
Если вы удалите последнюю строку, вы создадите новую act Activity, но ваш старый экземпляр все равно будет жив.
Вам нужно перезапустить Activity, как при изменении ориентации (т.е. ваше состояние сохраняется и передается на onCreate(Bundle) )?
Если вы этого не сделаете, одним из возможных способов решения проблемы будет использование одной дополнительной фиктивной операции, которая будет запущена из первого действия, и какая задача — запустить новый экземпляр. Или просто задержать вызов act.finish() , после запуска нового.
Если вам нужно сохранить большую часть состояния, вы попадаете в довольно глубокие воды, потому что это нетривиально, чтобы передать все свойства вашего состояния, особенно без утечки старого Контекста/Действия, передав его новому экземпляр.
Пожалуйста, укажите, что вы пытаетесь сделать.
Источник
Перезагрузить активность в Android
это хорошая практика, чтобы перезагрузить Activity на Android?
что было бы лучшим способом сделать это? this.finish а то this.startActivity активность Intent ?
14 ответов
Вы можете просто использовать
обновление Activity изнутри.
это то, что я делаю, чтобы перезагрузить действие после изменения возврата из изменения предпочтений.
это по существу заставляет активность перерисовывать себя.
обновление: лучший способ сделать это-вызвать recreate() метод. Это приведет к воссозданию активности.
для тех, кто не хочет видеть, что мигает после recreate () метод просто использовать
Мне нужно было срочно обновить список сообщений в одном из моих приложений, поэтому я просто выполнил обновление моей основной активности пользовательского интерфейса, прежде чем закрыть диалоговое окно, в котором я был. Я уверен, что есть и лучшие способы добиться этого.
Android включает в себя систему управления процессами, которая обрабатывает создание и уничтожение деятельности, которая в значительной степени отрицает любую выгоду, которую вы увидите от ручного перезапуска деятельности. Вы можете посмотреть дополнительную информацию о нем по адресу Основы Применения
хорошая практика заключается в том, чтобы гарантировать, что ваши методы onPause и onStop освобождают любые ресурсы, которые вам не нужно удерживать и использовать onLowMemory уменьшить ваши потребности деятельностей до абсолютного минимума.
Источник
Как перезапустить Android-активность
Как перезапустить Android- Activity ? Я попробовал следующее, но Activity просто уходит.
Я сделал свой видеомикшер следующим образом:
В принципе, я сначала вызываю finish() , и я использую то же самое намерение, с которого была начата эта деятельность. Кажется, это трюк?
ОБНОВЛЕНИЕ: Как указано Ральфом ниже, Activity.recreate() – это путь в API 11 и далее. Это предпочтительнее, если вы находитесь в среде API11 +. Вы можете проверить текущую версию и вызывать фрагмент кода выше, если вы используете API 10 или ниже. (Пожалуйста, не забудьте оставить ответ Ральфа!)
Начиная с уровня API 11 (Honeycomb), вы можете вызвать метод recreate () активности (благодаря этому ответу).
Метод recreate () действует так же, как изменение конфигурации, поэтому также вызывают методы onSaveInstanceState () и onRestoreInstanceState (), если это применимо.
Перед SDK 11 способ сделать это выглядит так:
Просто чтобы совместить ответы Ральфа и Бена (включая изменения, сделанные в комментариях):
Это решение сработало для меня.
Сначала закончите операцию, а затем запустите ее снова.
Вызовите этот метод
Даже если на это ответили несколько раз.
Если перезапустить активность из фрагмента, я бы сделал так:
Значит, вы думаете, что это немного переборщило? Но проводка Handler позволяет вам вызвать это в методе жизненного цикла. Я использовал это в onRestart / onResume при проверке, изменилось ли состояние между пользователем, возвращающимся в приложение. (Что-то установил).
Без Handler если вы вызываете его в нечетном месте, он просто убьет действие и не перезапустит его.
Не стесняйтесь задавать любые вопросы.
Я использовал этот код, чтобы до сих пор поддерживать старые версии Android и использовать recreate() для новых версий Android.
Ну, это не список, а комбо некоторых, которые уже опубликованы:
Это самый простой способ перезапустить текущую деятельность:
На самом деле, следующий код действителен для уровней API 5 и выше, поэтому, если ваш целевой API ниже этого, вы получите нечто очень похожее на код EboMike.
Существует один хакерский подход, который должен работать над любой деятельностью, включая основную.
Когда изменения ориентации, Android обычно воссоздает вашу деятельность (если вы не переопределите ее). Этот метод полезен для поворотов на 180 градусов, когда Android не воссоздает вашу активность.
Попытайтесь использовать это ..
В сочетании со странным поведением SurfaceView LifeCycle с камерой . Я обнаружил, что recreate () не очень хорошо работает с жизненным циклом SurfaceViews. SurfaceDestroyed никогда не называется во время цикла отдыха. Он вызывается после onResume (странно), после чего мой SurfaceView уничтожается.
Исходный способ воссоздания деятельности отлично работает.
Я не могу точно понять, почему это так, но это просто наблюдение, которое, как мы надеемся, будет направлять других в будущем, поскольку оно устраняет мои проблемы с SurfaceViews
Если вы удалите последнюю строку, вы создадите новую act Activity, но ваш старый экземпляр останется в живых.
Вам нужно перезапустить Activity, как при изменении ориентации (т.е. ваше состояние сохраняется и передается в onCreate(Bundle) )?
Если вы этого не сделаете, одним из возможных способов решения проблемы будет использование одной дополнительной фиктивной операции, которая будет запущена из первого действия, и какая задача – запустить новый экземпляр. Или просто задерживайте вызов act.finish() после запуска нового.
Если вам нужно сохранить большую часть состояния, вы попадаете в довольно глубокие воды, потому что нетривиально передавать все свойства вашего состояния, особенно без утечки старого контекста / действия, передавая его новому экземпляру.
Пожалуйста, укажите, что вы пытаетесь сделать.
Решение по вашему вопросу:
Чтобы начать новую деятельность, необходимо включить в контекст активности, а также завершить текущую деятельность.
Надеюсь, это полезно .. и работает для меня.
Если вы вызываете какой-то фрагмент, то делайте ниже кода.
Вызовите метод onCreate. Например onCreate(null);
Источник
Жизненный цикл Android
Жизненный цикл Android
Понимание жизненного цикла Android и изменения его состояния имеет решающее значение для создания приложений с меньшим количеством ошибок, использующих меньше ресурсов и обеспечивающих хорошее взаимодействие с пользователем.
Когда дело доходит до создания приложения на Android, активити и фрагменты являются ключевыми компонентами для создания пользовательского интерфейса (UI). Когда пользователь перемещается по приложению, эти компоненты проходят через разные состояния жизненного цикла Android.
Понимание жизненного цикла и правильная реакция на изменения его состояния имеют решающее значение. Он позволяет создавать приложения с меньшим количеством ошибок, использовать меньше системных ресурсов Android и обеспечивать хорошее взаимодействие с пользователем.
В этом туториале вы познакомитесь с простым приложением PuppyCounter, которое можно использовать для подсчета собак во время прогулки по окрестностям. Вы узнаете:
- Роль жизненного цикла в Android приложениях.
- Основы жизненных циклов активити и фрагментов, а также колбэки (обратные вызовы), вызываемые, когда действие перемещается между состояниями жизненного цикла.
- Как сохранить и восстановить состояние экземпляра активити.
- Процесс передачи данных между активити и фрагментами.
- Как ViewModel может помочь вам хранить и управлять данными, связанными с пользовательским интерфейсом с учетом жизненного цикла.
Для этого урока вам понадобится Android Studio и Android-устройство или эмулятор.
Начнем
Для начала загрузите материалы. Откройте стартовый проект в Android Studio. Как только проект откроется, дайте ему запуститься и синхронизироваться, и вы будете готовы к работе!
Запустите приложение и проверьте его возможности:
В приложении два экрана:
- Главный экран: позволяет подсчитывать собак разных размеров. Вы можете нажимать на карточки или на кнопки «плюс» и «минус», чтобы обновить счетчики. На верхней панели у вас есть две кнопки: первая сбрасывает значения, а вторая открывает экран «Share» (Поделиться).
- Экран Share: показывает количество ваших собак. Нажмите на «Share», чтобы открыть диалоговое окно, в котором вас спросят, хотите ли вы поделиться своим счетом. В этом туториале вы не реализуете эту логику, но можете притвориться, что она существует. :]
Затем ознакомьтесь со структурой проекта:
Как видите, много, что для вас уже приготовлено. Самые важные пакеты — это активити и фрагменты. Вы будете перемещаться между ними, когда узнаете об активити и жизненном цикле фрагмента. Прямо сейчас не беспокойтесь о деталях. Вы познакомитесь с классами внутри по мере прохождения данного туториала. Помимо этих пакетов, обратите внимание на следующие три вещи:
- DogCount: класс модели для ваших данных.
- SplashActivity: активити, которая открывается при запуске приложения.
- PuppyCounterApplication: класс приложения.
Прежде чем вдаваться в подробности жизненного цикла активити, рассмотрим некоторую предысторию роли жизненного цикла в приложениях Android.
Понимание роли жизненного цикла приложений
Операционная система (ОС) Android — это многопользовательская система Linux. В большинстве случаев каждое приложение работает в собственном процессе Linux. ОС создает процесс, когда необходимо выполнить любой из компонентов приложения. Когда ни один компонент приложения не запущен, а ОС требуется освободить память для запуска других приложений, процесс прерывается.
ОС Android использует иерархию по важности, чтобы определить, какие процессы оставить в живых или уничтожить. В этой иерархии процессы делятся на разные типы. Этот тип зависит от запущенных в данный момент компонентов приложения и их текущего состояния.
Самый распространенный компонент приложения — Activity. Каждое приложение для Android имеет одно или несколько активити. Когда пользователь перемещается по приложению, действия проходят через разные состояния жизненного цикла.
Разработчики должны понимать, как различные компоненты влияют на время жизни процесса. Неправильное использование этих компонентов может привести к тому, что система остановит процесс, пока выполняет важную работу.
Изучение жизненного цикла активности
На рисунке выше показаны различные состояния, через которые происходит активность в течение своего жизненного цикла:
- Initialized: создается экземпляр активити и инициализируются его свойства.
- Created: активити теперь полностью инициализировано и готово к настройке своего пользовательского интерфейса.
- Started: активити видна пользователю.
- Resumed: активити видна пользователю и находится в фокусе. В этом состоянии пользователь, скорее всего, взаимодействует с активити.
- Destroyed: активити уничтожена, и ОС может освободить свою память.
Обратите внимание на разные колбэки (обратные вызовы) между состояниями. ОС вызывает эти колбэки, когда активити переходит из одного состояния в другое. Вы можете переопределить эти методы в своих активити, чтобы выполнять задачи в ответ на эти изменения состояния жизненного цикла.
Прежде чем объяснять каждый колбэк, проверьте их в действии. Откройте MainActivity.kt и добавьте логирование в onCreate() и onResume() . Также переопределите другие колбэки:
Всякий раз, когда вы переопределяете такой колбэк, убедитесь, что вы также вызываете метод суперкласса. Если вы этого не сделаете, ваше приложение не выполнит какую-то важную работу и может вылететь или зависнуть.
Скомпилируйте и запустите приложение. Затем проверьте логи. Чтобы просмотреть логи в Android Studio, откройте инструмент Logcat, щелкнув Logcat внизу на странице. Введите PuppyCounter в историю поиска, чтобы показать результаты:
Затем закройте приложение, нажав назад, или проведите пальцем в обратном направлении, если у вас включена навигация с помощью жестов. Еще раз проверьте логи. Вы должны увидеть что-то вроде этого:
Заметка
В логах вы не увидите сообщение «Back button clicked» (Нажата кнопка назад). Мы добавили это в изображение, чтобы вам было легче заметить нажатия кнопок.
Понимание колбэков жизненного цикла активити
Вы только что прошли один полный жизненный цикл активити: активити была создана, возобновлена и окончательно уничтожена, когда вы вышли из приложения.
На приведенной выше диаграмме представлен жизненный цикл активити:
- onCreate(): активити переходит в состояние Создано. Здесь вы выполняете логику, которая должна выполняться только один раз за все время активити. Сюда можно включить настройку контент вью, связывание активити с ViewModel, создание экземпляров некоторых переменных области класса и т.д.
- onStart(): активити переходит в состояние Начато. Этот вызов делает активити видимой для пользователя, поскольку приложение готовится к тому, чтобы активити перешла на передний план и стала интерактивной.
- onResume(): активити переходит в состояние Возобновлено. Теперь пользователь может взаимодействовать с активити. Здесь вы можете включить любую функциональность, которая должна работать, пока компонент виден и находится на переднем плане.
- onPause(): активити переходит в состояние Приостановлено. Этот вызов указывает на то, что активити больше не находится на переднем плане, хотя она может быть видна, например, если пользователь находится в многооконном режиме. В это время вам следует приостановить или настроить операции, которые не должны продолжаться или должны продолжаться в модерации. Действие остается в этом состоянии до возобновления активити, например, открытия или закрытия нижнего листа в действии, или до тех пор, пока оно не станет полностью невидимым для пользователя, например, при открытии другого действия.
- onStop(): активити переходит в состояние Остановлено. Активити больше не видна пользователю. Здесь вы должны освободить или настроить ресурсы, которые не нужны, пока активити не видна пользователю. Вы также должны использовать эту возможность для выполнения операций выключения для задач, которые относительно интенсивно загружают процессор, например, для операций с базой данных.
- onDestroy(): активити переходит в состояние Уничтожено. На этом работа заканчивается. Это может быть потому, что:
- Пользователь полностью закрывает активити.
- finish() вызывается для активити.
- Система временно прерывает активити из-за изменения конфигурации, например поворота устройства или многооконного режима.
Бывают ситуации, когда система убивает процесс, следовательно, не вызывает onDestroy() или любые другие методы жизненного цикла активити. Таким образом, его не следует использовать для того, чтобы делать те вещи, которые должны остаться после завершения процесса.
Заметка
Дополнительные сведения о жизненном цикле Activity смотрите в Android Developer documentation.
Сохранение и восстановление состояния экземпляра активити
Если вы немного поиграли с приложением, то возможно, заметили пару ошибок. Счетчик увеличивается при нажатии карточек на главном экране.
Теперь поверните устройство, чтобы изменить ориентацию экрана. Если на дисплее вашего устройства включен автоповорот, вы увидите что-то вроде этого:
Состояние счетчика обнулилось при смене ориентации экрана. Посмотрим логи:
Вы можете видеть, что когда поменялась ориентация экрана, приложение уничтожило активити в портретной ориентации, а затем создало и возобновило новую активити в горизонтальной ориентации. Поскольку в MainActivity.kt у вас нет никакой логики для сохранения и восстановления состояния счетчика, действие было потеряно во время этого процесса.
Скоро мы это исправим!
Сохранение состояния экземпляра
Откройте MainActivity.kt и добавьте следующий код:
Когда активити начинает останавливаться, ОС вызывает onSaveInstanceState() , чтобы действие сохранило любую информацию о состоянии в бандле сохранения состояния. Некоторые вью Android обрабатывают по умолчанию — EditText для текста и ListView для позиции прокрутки.
Заметка
OnSaveInstanceState() не вызывается, когда пользователь явно закрывает активити или когда вызывается finish() .
Чтобы сохранить состояние dogCount , вы переопределили onSaveInstanceState() и сохранили состояние в Bundle как пару ключ-значение с помощью outState.putParcelable() . В качестве ключа вы использовали STATE_DOG_COUNT , который уже был определен в классе.
Проверьте класс DogCount . Вы заметите, что он реализует Parcelable . Если вы не знакомы с Parcelable — это интерфейс, концептуально похожий Serializable в Java . Классы, реализующие Parcelable , могут быть записаны и восстановлены из Parcel , который разработан для высокопроизводительного транспорта IPC (IPC transport). Проще говоря, он позволяет хранить простые структуры данных в Bundle .
Восстановление состояния
Прекрасно! Теперь у вас есть логика для сохранения состояния, но в ней нет пользы, пока у вас нет логики для ее получения. В MainActivity.kt добавьте следующий код ниже onSaveInstanceState() :
Любое состояние, которое вы сохраняете в onSaveInstanceState() , вы можете восстановить в onRestoreInstanceState() . onRestoreInstanceState() получает Bundle , который содержит пары ключ-значение, которые вы можете прочитать. Здесь вы использовали saveInstanceState.getParcelable() для получения состояния DogCount . Обратите внимание, что вы использовали тот же ключ, что и для сохранения состояния: STATE_DOG_COUNT .
Заметка
ОС вызывает onRestoreInstanceState() после обратного вызова onStart( ) , только если у нее есть сохраненное состояние для восстановления. Вы также можете восстановить состояние в onCreate() , потому что этот колбэк получает тот же Bundle .
Запустите приложение. Увеличьте значения счетчиков и поменяйте ориентацию экрана:
Также проверьте логи, когда все колбеки будут вызваны, вы увидите следующую картину:
Заметка
Не путайте onSaveInstanceState() и onRestoreInstanceState() с колбеками жизненного цикла активности. ОС вызывает эти методы только в тот момент, когда это нужно.
Отлично! Теперь, когда вы исправили ошибку в приложении, пора перейти к следующей. 🙂
Передача данных между экранами
Увеличьте значения счетчиков на главном экране, а затем откройте экран «Share». Вы заметите, что значения экрана «Share» не совпадают со значениями на главном экране.
В MainActivity.kt измените showShareScreen() следующим образом:
С помощью этого кода вы сохраняете состояние DogCount в Intent . Здесь вы используете подход, аналогичный тому, что вы видели в предыдущем разделе. Да, этим вы передадите данные в ShareActivity, но вам все равно нужно добавить логику для их получения.
В ShareActivity.kt добавьте следующий метод:
Этот метод извлекает объект Intent , который запустил это действие, и пытается получить дополнительные данные, которые были переданы с ним. В этом конкретном случае он попытается получить состояние DogCount .
Чтобы завершить логику получения, вызовите этот метод в onCreate() в ShareActivity.kt:
При получении данных из Intent лучше всего это сделать в onCreate() . Таким образом, у вас будет время настроить состояние до того, как действие возобновится и пользователь начнет с ним взаимодействовать.
Супер! Запустите приложение. Увеличьте значения счетчиков и откройте экран «Share». Вы увидите что-то вроде этого:
Проверьте логи, чтобы увидеть жизненные циклы активити при переходе от одного экрана к другому.
Обратите внимание, как ОС создает ShareActivity сразу после вызова onPause() MainActivity. Как упоминалось ранее, приложение вызывает onStop() , когда активити больше не видна пользователю. После вызова onPause() MainActivity вы можете увидеть серию колбэков жизненного цикла ShareActivity, которые включают чтение intent данных. После возобновления ShareActivity полностью виден пользователю, и может быть вызвана функция MainActivity onStop() , за которой следует onSaveInstanceState() .
Разбираем данные объекта Intent
Измените ориентацию экрана на экране Share и обратите внимание на то, что происходит. Вы увидите, что приложение сохранило состояние dogCount . Как это возможно, если вы не реализовали логику для сохранения и получения состояния экземпляра?
Вы уже знакомы с тем, как состояние может быть потеряно во время изменения конфигурации. В этом случае обратите внимание на то, что лог readExtras() снова присутствует, когда приложение создает новый ShareActivity. Но если вы проверите код, вы увидите, что вы распечатываете этот лог, только если intent.extras отличается от null — или, другими словами, Intent содержит некоторые данные.
Данные, которые вы передаете с помощью Intent при запуске новой активити, сохраняются при воссоздании активити.
Чтобы завершить этот раздел, нажмите назад, когда экран находится в горизонтальной ориентации, и еще раз просмотрите логи.
ShareActivity приостановлен, а старая портретная активность MainActivity уничтожена. Затем создается и возобновляется новая горизонтальная MainActivity . Наконец, приложение вызывает onStop() и onDestroy() ShareActivity.
Отлично! Теперь, когда вы понимаете жизненный цикл активности и то, как правильно управлять состоянием активити, пора переходить к фрагментам. 🙂
Изучение жизненного цикла фрагмента
Как и у активити, у фрагментов есть свой жизненный цикл. Когда пользователь перемещается по вашему приложению и взаимодействует с ним, ваши фрагменты переходят из одного состояния в другое в своем жизненном цикле, когда они добавляются, удаляются, а также выходят на экран или выходят из него.
На рисунке выше вы можете видеть, что жизненный цикл фрагмента аналогичен жизненному циклу активити, но содержит некоторые дополнительные методы, специфичные для фрагмента. Прежде чем объяснять каждый колбэк, проверьте их в приложении.
В предыдущем разделе вы поиграли с двумя активити и увидели, как меняется их жизненный цикл при перемещении между экранами. В этом примере вы реализуете те же экраны с фрагментами. Вы можете найти два фрагмента, которые представляют каждый экран в пакете фрагментов: MainFragment.kt и ShareFragment.kt. Также есть одна активити контейнера и пакет viewmodels. Пока не обращайте внимания на пакет viewmodels. Он понадобится вам в следующем разделе.
Если вы проверите MainFragment.kt, вы заметите много общего с MainActivity.kt. У них одинаковая логика управления состояниями, но MainFragment.kt содержит еще несколько колбэков жизненного цикла.
Перед запуском приложения откройте SplashActivity.kt и обновите startFirstActivity() , чтобы он запускал ActivityWithFragments вместо MainActivity :
Отлично! Теперь соберите и запустите приложение. Затем осмотрите логи.
Обратите внимание, как жизненный цикл фрагмента синхронизируется с жизненным циклом активности. Сначала приложение создает и запускает ActivityWithFragments. После этого он создает и запускает фрагмент и его просмотр. Наконец, он возобновляет как активити, так и фрагмент.
Далее нажмите назад и снова наблюдайте за логами.
Закрыв приложение, вы запустили процесс уничтожения активити. Как и раньше, события жизненного цикла фрагмента следуют за событиями жизненного цикла активити. И активити, и фрагмент сначала приостанавливаются, затем останавливаются и, наконец, уничтожаются.
Состояние жизненного цикла фрагмента никогда не может быть выше, чем у его родительского. Например, родительский фрагмент или активити должны начинаться до его дочерних фрагментов. Точно так же дочерние фрагменты должны останавливаться до их родительского фрагмента или активности. Из приведенных выше логов можно подумать наоборот — что сначала останавливается действие, но это только потому, что вы распечатываете логи как первый вызов в колбэках жизненного цикла. Внутренне ОС обеспечивает остановку всех дочерних фрагментов перед остановкой активити.
Понимание обратных вызовов жизненного цикла фрагмента
Теперь вы можете немного глубже погрузиться в каждое событие жизненного цикла, чтобы лучше понять жизненный цикл фрагмента:
- onCreate(): фрагмент достигает состояния Created. Подобно onCreate() активити, этот колбэк получает Bundle , содержащий любое состояние, ранее сохраненное onSaveInstanceState() .
- onCreateView(): вызывается для расширения или создания вью фрагмента.
- onViewCreated(): вью фрагмента создается с ненулевым объектом View. Это представление устанавливается для фрагмента и может быть получено с помощью getView() .
- onStart(): фрагмент переходит в состояние Started. В этом состоянии гарантируется, что вью фрагмента доступно и безопасно выполнить FragmentTransaction для дочернего FragmentManager фрагмента.
- onResumed(): фрагмент переходит в состояние Resumed. Он становится видимым после завершения всех эффектов Animator и Transition . Теперь пользователь может взаимодействовать с фрагментом.
- onPause(): фрагмент возвращается в состояние Started. ОС вызывает этот колбэк, когда пользователь начинает покидать фрагмент, пока фрагмент все еще виден.
- onStop(): фрагмент возвращается в состояние Created и больше не отображается.
- onDestroyView(): запускается после завершения всех анимаций выхода и переходов, когда представление фрагмента было отделено от окна. На этом этапе все ссылки на представление фрагмента должны быть удалены, что позволит очистить представление фрагмента от мусора.
- onDestroy(): фрагмент переходит в состояние Destroyed. Это происходит при удалении фрагмента или при уничтожении FragmentManager . На этом этапе жизненный цикл фрагмента подошел к концу.
Теперь, когда вы лучше понимаете, что скрывается под капотом, переходите между основным экраном и экраном Share, чтобы увидеть танец жизненного цикла фрагмента. 🙂
Как вы видели в этом и предыдущем разделе, жизненный цикл Android довольно сложен. Управлять состояниями и взаимодействовать с пользовательским интерфейсом в нужное время может быть непросто для неопытных разработчиков. Это привело к появлению некоторых новых API и компонентов Android, которые должны облегчить жизнь всем разработчикам Android. Одним из таких компонентов является ViewModel.
Использование ViewModel для хранения данных пользовательского интерфейса
ViewModel предназначен для хранения данных, связанных с пользовательским интерфейсом, и управления ими с учетом жизненного цикла.
Во-первых, замените логику сохранения и восстановления состояния в MainFragment.kt подходом, использующим ViewModel .
В пакете viewmodels создайте новый класс с именем MainViewModel.kt.
Это будет ViewModel для вашего главного экрана. Вы будете использовать его для сохранения состояния DogCount . Используйте _dogCount для отслеживания состояния и dogCount для отображения его наблюдателям. Для обновления состояния используйте setDogCount() .
Если вы хотите узнать больше о LiveData , обратитесь к Android Developer documentation.
В MainFragment.kt добавьте следующее:
Добавьте следующую строку выше onCreate() :
Таким образом, вы добавили код для создания MainViewModel для MainFragment .
Затем добавьте в MainFragment.kt следующий метод:
Этот метод позволяет вам подписаться на наблюдаемое состояние в MainViewModel . Каждый раз, когда состояние dogCount изменяется, приложение передает новое состояние во вью, и с новым состоянием вызывается renderDogCount() , в результате чего пользовательский интерфейс обновляется.
Затем измените onViewCreated() , чтобы подписаться на MainViewModel после вызова суперкласса:
Вам также понадобится логика, которая обновит состояние в MainViewModel . Измените updateDogCount() следующим образом:
Этот метод вызывается всякий раз, когда пользователь обновляет счетчики. Он обновит MainViewModel с новым состоянием. MainViewModel протолкнет это состояние через dogCount , и MainFragment получит уведомление, поскольку он подписан на MainViewModel .
Наконец, в MainFragment удалите onSaveInstanceState() , вызов renderDogCount (dogCount) из onResume() и код saveInstanceState? .Run <. >в onCreate() . Вам это больше не нужно. 🙂
Скомпилируйте и запустите приложение. Коснитесь счетчиков пару раз и поверните экран. Вы должны увидеть что-то вроде этого:
На приведенном ниже рисунке можно увидеть время жизни ViewModel рядом с соответствующим жизненным циклом действия.
Объекты ViewModel привязаны к Lifecycle , передаваемому ViewModelProvider при получении ViewModel . Он остается в памяти до тех пор, пока Lifecycle , на который он рассчитан, не исчезнет навсегда. В случае активити это происходит, когда она завершена. Для фрагмента это происходит, когда он отсоединяется.
Источник