По мере того, как пользователь перемещается по вашему приложению, выходит из него и возвращается обратно, Activity экземпляры вашего приложения переходят через различные состояния в своем жизненном цикле. Класс Activity предоставляет ряд обратных вызовов, которые позволяют действию узнать, что состояние изменилось: что система создает, останавливает или возобновляет действие или уничтожает процесс, в котором находится действие.
В методах обратного вызова жизненного цикла вы можете объявить, как ведет себя ваша активность, когда пользователь покидает ее и снова входит в нее. Например, если вы создаете проигрыватель потокового видео, вы можете приостановить воспроизведение видео и разорвать сетевое соединение, когда пользователь переключится на другое приложение. Когда пользователь вернется, вы можете повторно подключиться к сети и позволить пользователю возобновить просмотр видео с того же места. Другими словами, каждый обратный вызов позволяет выполнять определенную работу, подходящую для данного изменения состояния. Выполнение нужной работы в нужное время и правильная обработка переходов делают ваше приложение более надежным и производительным. Например, хорошая реализация обратных вызовов жизненного цикла может помочь вашему приложению избежать:
- Сбой, если пользователь получает телефонный звонок или переключается на другое приложение во время использования вашего приложения.
- Потребление ценных системных ресурсов, когда пользователь не использует их активно.
- Потеря пользовательского прогресса, если он покинет ваше приложение и вернется к нему позже.
- Сбой или потеря пользовательского прогресса при повороте экрана между альбомной и портретной ориентацией.
В этом документе подробно объясняется жизненный цикл активности. Документ начинается с описания парадигмы жизненного цикла. Затем он объясняет каждый из обратных вызовов: что происходит внутри во время их выполнения и что вы должны реализовать во время них. Затем в нем кратко представлена взаимосвязь между состоянием активности и уязвимостью процесса перед уничтожением системой. Наконец, в нем обсуждаются несколько тем, связанных с переходами между состояниями активности.
Сведения об управлении жизненными циклами, включая рекомендации по передовым методам, см. в разделах Обработка жизненных циклов с помощью компонентов с поддержкой жизненного цикла и Сохранение состояний пользовательского интерфейса . Чтобы узнать, как спроектировать надежное приложение производственного качества, используя действия в сочетании с архитектурными компонентами, см. Руководство по архитектуре приложений .
Концепции жизненного цикла Activity
Для перехода между этапами жизненного цикла действия класс Activity предоставляет базовый набор из шести обратных вызовов: onCreate(), onStart(), onResume(), onPause(), onStop() и onDestroy(). Система вызывает каждый из этих обратных вызовов, когда действие переходит в новое состояние.
На рис. 1 представлено визуальное представление этой парадигмы.
Когда пользователь начинает покидать действие, система вызывает методы для демонтажа действия. В некоторых случаях этот демонтаж является лишь частичным; действие все еще находится в памяти (например, когда пользователь переключается на другое приложение) и все еще может вернуться на передний план. Если пользователь возвращается к этому действию, действие возобновляется с того места, где пользователь остановился. За некоторыми исключениями приложениям запрещено запускать действия, когда они работают в фоновом режиме .
Вероятность того, что система уничтожит данный процесс — вместе с действиями в нем — зависит от состояния действия в данный момент. Состояние активности и выброс из памяти предоставляет больше информации о взаимосвязи между состоянием и уязвимостью к выбросу.
В зависимости от сложности вашей деятельности вам, вероятно, не нужно реализовывать все методы жизненного цикла. Однако важно, чтобы вы понимали каждый из них и реализовывали те из них, которые гарантируют, что ваше приложение ведет себя так, как ожидают пользователи.
В следующем разделе этого документа подробно описаны обратные вызовы, которые вы используете для обработки переходов между состояниями.
Обратные вызовы жизненного цикла
В этом разделе представлена концептуальная информация и информация о реализации методов обратного вызова, используемых в течение жизненного цикла действия.
Некоторые действия, такие как вызов setContentView(), относятся к методам жизненного цикла активности. Однако код, реализующий действия зависимого компонента, должен быть размещен в самом компоненте. Для этого необходимо сделать так, чтобы зависимый компонент учитывал жизненный цикл. См. раздел Управление жизненными циклами с помощью компонентов с поддержкой жизненного цикла, чтобы узнать, как сделать так, чтобы зависимые компоненты учитывали жизненный цикл.
onCreate( )
Вы должны реализовать этот обратный вызов, который срабатывает, когда система впервые создает activity. При создании действия оно переходит в состояние Создано . В onCreate() методе вы выполняете базовую логику запуска приложения, которая должна произойти только один раз за все время activity. Например, ваша реализация onCreate() может привязывать данные к спискам, связывать действие с объектом ViewModel и создавать экземпляры некоторых переменных области класса. Этот метод получает параметр savedInstanceState, который является объектом Bundle, содержащим ранее сохраненное состояние активности. Если действие никогда не существовало ранее, значение объекта Bundle равно null.
Если у вас есть компонент, поддерживающий жизненный цикл, который подключен к жизненному циклу вашей деятельности, он получит ON_CREATE событие. Будет вызван метод, аннотированный @OnLifecycleEvent, чтобы ваш компонент, поддерживающий жизненный цикл, мог выполнить любой код настройки, необходимый для созданного состояния.
В следующем примере onCreate() метода показана основная настройка действия, например объявление пользовательского интерфейса (определенного в файле макета XML), определение переменных-членов и настройка некоторых элементов пользовательского интерфейса. В этом примере файл макета XML указывается путем передачи идентификатора ресурса файла R.layout.main_activityв setContentView().
//Kotlin
lateinit var textView: TextView
// some transient state for the activity instance
var gameState: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
// call the super class onCreate to complete the creation of activity like
// the view hierarchy
super.onCreate(savedInstanceState)
// recovering the instance state
gameState = savedInstanceState?.getString(GAME_STATE_KEY)
// set the user interface layout for this activity
// the layout file is defined in the project res/layout/main_activity.xml file
setContentView(R.layout.main_activity)
// initialize member TextView so we can manipulate it later
textView = findViewById(R.id.text_view)
}
// This callback is called only when there is a saved instance that is previously saved by using
// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore
// other state here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}
// invoked when the activity may be temporarily destroyed, save the instance state here
override fun onSaveInstanceState(outState: Bundle?) {
outState?.run {
putString(GAME_STATE_KEY, gameState)
putString(TEXT_VIEW_KEY, textView.text.toString())
}
// call superclass to save any view hierarchy
super.onSaveInstanceState(outState)
}
В качестве альтернативы определению XML-файла и передаче его в setContentView(), вы можете создавать новые View объекты в коде своей активности и строить иерархию представлений, вставляя новые Views в файл ViewGroup. Затем вы используете этот макет, передав корень ViewGroup в setContentView(). Дополнительные сведения о создании пользовательского интерфейса см. в документации по пользовательскому интерфейсу .
Ваша activity не находится в состоянии Created. После onCreate() завершения выполнения метода действие переходит в состояние Started, и система быстро вызывает методы onStart() и onResume() в быстрой последовательности. В следующем разделе объясняется onStart() обратный вызов.
onStart()
Когда действие переходит в состояние Started, система вызывает этот обратный вызов. Вызов onStart() делает действие видимым для пользователя, поскольку приложение готовится к тому, чтобы действие вышло на передний план и стало интерактивным. Например, в этом методе приложение инициализирует код, поддерживающий пользовательский интерфейс.
Когда действие переходит в запущенное состояние, любой компонент, поддерживающий жизненный цикл, связанный с жизненным циклом действия, получит ON_START событие.
Метод onStart() завершается очень быстро, и, как и в случае с состоянием Created, активность не остается резидентной в состоянии Started. После завершения этого обратного вызова действие переходит в состояние Resumed , и система вызывает onResume() метод.
onResume( )
Когда действие переходит в состояние «Возобновлено», оно выходит на передний план, а затем система вызывает onResume() обратный вызов. Это состояние, в котором приложение взаимодействует с пользователем. Приложение остается в этом состоянии до тех пор, пока что-то не отвлечет внимание от приложения. Таким событием может быть, например, получение телефонного звонка, переход пользователя к другому действию или выключение экрана устройства.
Когда действие переходит в состояние возобновления, любой компонент, поддерживающий жизненный цикл, связанный с жизненным циклом действия, получит ON_RESUME событие. Именно здесь компоненты жизненного цикла могут активировать любую функциональность, которая должна работать, когда компонент виден и находится на переднем плане, например запуск предварительного просмотра камеры.
Когда происходит прерывающее событие, действие переходит в состояние Paused , и система вызывает onPause() обратный вызов.
Если действие возвращается в состояние «Возобновлено» из состояния «Приостановлено», система еще раз вызывает onResume() метод. По этой причине вы должны реализовать onResume() инициализацию компонентов, которые вы освобождаете во время onPause(), и выполнять любые другие инициализации, которые должны выполняться каждый раз, когда действие переходит в состояние возобновлено.
Вот пример компонента с учетом жизненного цикла, который обращается к камере, когда компонент получает ON_RESUME событие:
//Kotlin
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun initializeCamera() {
if (camera == null) {
getCamera()
}
}
...
}
Приведенный выше код инициализирует камеру после LifecycleObserver получает событие ON_RESUME. Однако в многооконном режиме ваша активность может быть полностью видна, даже если она находится в состоянии паузы. Например, когда пользователь находится в многооконном режиме и касается другого окна, в котором нет вашей активности, ваша активность перейдет в состояние «Приостановлено». Если вы хотите, чтобы камера была активна только тогда, когда приложение возобновлено (видно и активно на переднем плане), инициализируйте камеру после события ON_RESUME, показанного выше. Если вы хотите, чтобы камера оставалась активной, пока действие приостановлено, но видима (например, в многооконном режиме), вам следует вместо этого инициализировать камеру после события ON_START. Однако обратите внимание, что если камера активна, когда ваша активность приостановлена, это может запретить доступ к камере другому возобновленному приложению в многооконном режиме. Иногда может быть необходимо держать камеру активной, пока ваша деятельность приостановлена, но это может фактически ухудшить общее впечатление от пользователя, если вы это сделаете. Тщательно продумайте, на каком этапе жизненного цикла более целесообразно взять под контроль общие системные ресурсы в контексте многооконности. Дополнительные сведения о поддержке многооконного режима см. Поддержка нескольких окон .
Независимо от того, какое событие сборки вы выбрали для выполнения операции инициализации, обязательно используйте соответствующее событие жизненного цикла для освобождения ресурса. Если вы инициализируете что-то после события ON_START, отпустите или завершите это после события ON_STOP. Если вы инициализируете после события ON_RESUME, отпустите после события ON_PAUSE.
Обратите внимание, что приведенный выше фрагмент кода помещает код инициализации камеры в компонент, поддерживающий жизненный цикл. Вместо этого вы можете поместить этот код непосредственно в обратные вызовы жизненного цикла активности, такие как onStart() и onStop() но это не рекомендуется. Добавление этой логики в независимый компонент, учитывающий жизненный цикл, позволяет повторно использовать компонент в нескольких действиях без дублирования кода. См. раздел Управление жизненными циклами с помощью компонентов с поддержкой жизненного цикла, чтобы узнать, как создать компонент с поддержкой жизненного цикла.
onPause()
Система вызывает этот метод как первое указание на то, что пользователь покидает вашу активность (хотя это не всегда означает, что активность уничтожается); это указывает на то, что активность больше не находится на переднем плане (хотя она все еще может быть видна, если пользователь находится в многооконном режиме). Используйте этот onPause() метод, чтобы приостановить или настроить операции, которые не должны продолжаться (или должны продолжаться умеренно), пока Activity объект находится в состоянии «Приостановлено», и которые вы ожидаете возобновить в ближайшее время. Существует несколько причин, по которым активность может войти в это состояние. Например:
- Некоторое событие прерывает выполнение приложения, как описано в разделе onResume(). Это самый распространенный случай.
- В Android 7.0 (API 24) или выше несколько приложений работают в многооконном режиме. Поскольку только одно из приложений (windows) имеет фокус в любой момент времени, система приостанавливает работу всех остальных приложений.
- Откроется новое полупрозрачное действие (например, диалог). Пока действие все еще частично видно, но не в фокусе, оно остается приостановленным.
Когда действие переходит в состояние паузы, любой компонент, поддерживающий жизненный цикл, связанный с жизненным циклом действия, получит ON_PAUSE событие. Именно здесь компоненты жизненного цикла могут остановить любые функции, которые не нужно запускать, пока компонент не находится на переднем плане, например, остановить предварительный просмотр камеры.
Вы также можете использовать этот onPause() метод для высвобождения системных ресурсов, дескрипторов датчиков (таких как GPS) или любых ресурсов, которые могут повлиять на срок службы батареи, когда ваша деятельность приостановлена и они не нужны пользователю. Однако, как упоминалось выше в разделе onResume(), приостановленная активность может быть полностью видна в многооконном режиме. Таким образом, вам следует рассмотреть возможность использования onStop() вместо onPause() для полного освобождения или настройки ресурсов и операций, связанных с пользовательским интерфейсом, для лучшей поддержки многооконного режима.
Следующий пример LifecycleObserver реакции на событие ON_PAUSE является аналогом приведенного выше примера события ON_RESUME, освобождая камеру, которая была инициализирована после получения события ON_RESUME:
//Kotlin
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun releaseCamera() {
camera?.release()
camera = null
}
...
}
Обратите внимание, что приведенный выше фрагмент кода размещает код выпуска камеры после того, как событие ON_PAUSE получено LifecycleObserver. Как упоминалось ранее, см. раздел «Обработка жизненных циклов с помощью компонентов, поддерживающих жизненный цикл» , чтобы узнать, как создать компонент, поддерживающий жизненный цикл.
onPause() выполнение очень короткое и не обязательно дает достаточно времени для выполнения операций сохранения. По этой причине вы не должны использовать onPause() для сохранения данных приложения или пользователя, выполнения сетевых вызовов или выполнения транзакций базы данных; такая работа может не завершиться до завершения метода. Вместо этого во время onStop(). Дополнительные сведения о подходящих операциях для выполнения во время onStop() см . в разделе onStop() . Дополнительные сведения о сохранении данных см. в разделе Сохранение и восстановление состояния активности .
Завершение onPause() метода не означает, что активность выходит из состояния Paused. Скорее, активность остается в этом состоянии до тех пор, пока она не возобновится или не станет полностью невидимой для пользователя. Если действие возобновляется, система снова вызывает onResume() обратный вызов. Если действие возвращается из состояния Paused в состояние Resumed, система сохраняет Activity резидентный экземпляр в памяти, вызывая этот экземпляр при вызове системы onResume(). В этом сценарии вам не нужно повторно инициализировать компоненты, которые были созданы во время любого из методов обратного вызова, ведущих к состоянию Resumed. Если активность становится полностью невидимой, система вызывает onStop(). В следующем разделе обсуждается onStop() обратный вызов.
onStop()
Когда ваша активность больше не видна пользователю, она переходит в состояние «Остановлено», и система вызывает onStop() обратный вызов. Это может произойти, например, когда только что запущенная активность занимает весь экран. Система также может вызывать onStop(), когда действие завершилось и вот-вот должно быть завершено.
Когда действие переходит в остановленное состояние, любой компонент, поддерживающий жизненный цикл, связанный с жизненным циклом действия, получит ON_STOP событие. Именно здесь компоненты жизненного цикла могут остановить любые функции, которые не нужно запускать, пока компонент не виден на экране.
В этом onStop() методе приложение должно освобождать или корректировать ресурсы, которые не нужны, пока приложение не видно пользователю. Например, ваше приложение может приостановить анимацию или переключиться с мелкозернистых на крупнозернистые обновления местоположения. Использование onStop() вместо onPause() гарантирует, что работа, связанная с пользовательским интерфейсом, продолжится, даже когда пользователь просматривает вашу активность в многооконном режиме.
Вы также должны использовать onStop() для выполнения относительно интенсивно использующих ЦП операций завершения работы. Например, если вы не можете найти более подходящее время для сохранения информации в базе данных, вы можете сделать это во время onStop(). В следующем примере показана реализация onStop() сохранения содержимого черновой заметки в постоянном хранилище:
//Kotlin
override fun onStop() {
// call the superclass method first
super.onStop()
// save the note's current draft, because the activity is stopping
// and we want to be sure the current note progress isn't lost.
val values = ContentValues().apply {
put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText())
put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle())
}
// do this update in background on an AsyncQueryHandler or equivalent
asyncQueryHandler.startUpdate(
token, // int token to correlate calls
null, // cookie, not used here
uri, // The URI for the note to update.
values, // The map of column names and new values to apply to them.
null, // No SELECT criteria are used.
null // No WHERE columns are used.
)
}
Обратите внимание, что приведенный выше пример кода использует SQLite напрямую. Вместо этого вы должны использовать Room, библиотеку постоянства, которая обеспечивает уровень абстракции над SQLite. Чтобы узнать больше о преимуществах использования Room и о том, как реализовать Room в своем приложении, см . руководство по библиотеке сохраняемости комнаты .
Когда ваша активность переходит в состояние Stopped, Activity объект остается резидентным в памяти: он поддерживает всю информацию о состоянии и членах, но не прикрепляется к оконному менеджеру. Когда действие возобновляется, оно вспоминает эту информацию. Вам не нужно повторно инициализировать компоненты, которые были созданы во время любого из методов обратного вызова, ведущих к состоянию Resumed. Система также отслеживает текущее состояние каждого View объекта в макете, поэтому, если пользователь вводит текст в EditText виджет, этот контент сохраняется, поэтому вам не нужно его сохранять и восстанавливать.
Примечание. Как только ваша активность будет остановлена, система может уничтожить процесс, содержащий активность, если системе потребуется восстановить память. Даже если система уничтожает процесс, когда действие остановлено, система по-прежнему сохраняет состояние View объектов (например, текст в EditText виджете) в Bundle (блок пар ключ-значение) и восстанавливает их, если пользователь переходит обратно к активность. Дополнительные сведения о восстановлении активности, к которой возвращается пользователь, см. в разделе Сохранение и восстановление состояния активности .
Из состояния «Остановлено» действие либо возвращается для взаимодействия с пользователем, либо действие завершает работу и уходит. Если активность возвращается, система вызывает onRestart(). Если Activity работа завершена, система вызывает onDestroy(). В следующем разделе объясняется onDestroy() обратный вызов.
onDestroy( )
onDestroy() вызывается перед уничтожением активности. Система вызывает этот обратный вызов, потому что:
- действие завершается (из-за того, что пользователь полностью закрыл действие или из-за finish() вызова действия), или
- система временно уничтожает активность из-за изменения конфигурации (например, ротация устройства или многооконный режим)
Когда действие переходит в состояние уничтожения, любой компонент, поддерживающий жизненный цикл, связанный с жизненным циклом действия, получит ON_DESTROY событие. Именно здесь компоненты жизненного цикла могут очистить все, что им нужно, прежде чем действие будет уничтожено.
Вместо того, чтобы помещать логику в свою активность, чтобы определить, почему она уничтожается, вы должны использовать ViewModel объект, содержащий соответствующие данные представления для вашей деятельности. Если действие будет воссоздано из-за изменения конфигурации, ViewModel не нужно ничего делать, поскольку оно будет сохранено и передано следующему экземпляру действия. Если действие не будет воссоздано, то у ViewModel будет onCleared() вызван метод, в котором он может очистить любые данные, которые ему нужны, перед тем, как быть уничтоженным.
Вы можете различить эти два сценария с помощью isFinishing() метода.
Если действие завершается, onDestroy() является последним обратным вызовом жизненного цикла, который получает действие. Если onDestroy() вызывается в результате изменения конфигурации, система немедленно создает новый экземпляр действия, а затем вызывает этот новый экземпляр в новой конфигурации. onCreate()
Обратный onDestroy() вызов должен освободить все ресурсы, которые еще не были освобождены более ранними обратными вызовами, такими как onStop().
Состояние Activity и выброс из памяти
Система убивает процессы, когда ей нужно освободить оперативную память; вероятность того, что система уничтожит данный процесс, зависит от состояния процесса в данный момент. Состояние процесса, в свою очередь, зависит от состояния выполняемой в процессе активности. В таблице 1 показана корреляция между состоянием процесса, состоянием активности и вероятностью завершения процесса системой.
Примечание. Эта таблица применима только в том случае, если в процессе не запущены другие типы компонентов приложения.
Вероятность | Состояние | Окончательное
быть убитым | процесса | состояние activity
---------------------------------------------------------------------------------
Наименее | Foreground (имеющий или | Resumed (возобновлено)
| получающий фокус) |
Меньше | Visible (без фокуса) | Started/paused (старт/пауза)
Более | Background (невидимый) | Stopped (остановлено)
Наиболее | Empty (пустой) | Destroyed (уничтожен)
Таблица 1. Связь между жизненным циклом процесса и состоянием activity
Система никогда не уничтожает активность напрямую, чтобы освободить память. Вместо этого он убивает процесс, в котором выполняется действие, уничтожая не только действие, но и все остальное, работающее в этом процессе. Чтобы узнать, как сохранить и восстановить состояние пользовательского интерфейса вашей активности в случае остановки процесса, инициированного системой, см. раздел Сохранение и восстановление состояния активности .
Пользователь также может завершить процесс, используя Диспетчер приложений в разделе «Настройки», чтобы закрыть соответствующее приложение.
Дополнительные сведения о процессах в целом см . в разделе Процессы и потоки . Дополнительные сведения о том, как жизненный цикл процесса связан с состояниями в нем действий, см. в разделе Жизненный цикл процесса на этой странице.
Сохранение и восстановление переходного состояния UI
Пользователь ожидает, что состояние пользовательского интерфейса действия останется неизменным при изменении конфигурации, например при повороте или переключении в многооконный режим. Однако система по умолчанию уничтожает действие, когда происходит такое изменение конфигурации, стирая любое состояние пользовательского интерфейса, хранящееся в экземпляре действия. Точно так же пользователь ожидает, что состояние пользовательского интерфейса останется прежним, если он временно переключится с вашего приложения на другое приложение, а затем вернется к вашему приложению позже. Однако система может уничтожить процесс вашего приложения, пока пользователь отсутствует, а ваша деятельность остановлена.
Когда действие уничтожается из-за системных ограничений, вы должны сохранить временное состояние пользовательского интерфейса, используя комбинацию ViewModel, onSaveInstanceState() и/или локального хранилища. Чтобы узнать больше об ожиданиях пользователей и поведении системы, а также о том, как наилучшим образом сохранить сложные данные о состоянии пользовательского интерфейса при инициированной системой активности и завершении процесса, см. раздел Сохранение состояния пользовательского интерфейса.
В этом разделе описывается, что такое состояние экземпляра и как реализовать метод onSaveInstance(), который является обратным вызовом самого действия. Если ваши данные пользовательского интерфейса просты и легковесны, например примитивный тип данных или простой объект (например, String), вы можете использовать только onSaveInstanceState() для сохранения состояния пользовательского интерфейса как при изменении конфигурации, так и при завершении процесса, инициированном системой. Однако в большинстве случаев следует использовать как ViewModel, так и onSaveInstanceState() (как описано в разделе Сохранение состояния пользовательского интерфейса ), поскольку onSaveInstanceState() влечет за собой затраты на сериализацию/десериализацию.
Состояние экземпляра
Есть несколько сценариев, в которых ваша активность уничтожается из-за нормального поведения приложения, например, когда пользователь нажимает кнопку «Назад» или ваша активность сигнализирует о своем уничтожении, вызывая finish() метод. Когда ваша активность уничтожается из-за того, что пользователь нажимает кнопку «Назад» или активность завершается сама по себе, концепция этого экземпляра как системы, так и пользователя Activity исчезает навсегда. В этих сценариях ожидания пользователя соответствуют поведению системы, и вам не нужно делать никакой дополнительной работы.
Однако, если система уничтожает действие из-за системных ограничений (таких как изменение конфигурации или нехватка памяти), то, хотя фактический Activity экземпляр исчез, система помнит, что он существовал. Если пользователь пытается вернуться к действию, система создает новый экземпляр этого действия, используя набор сохраненных данных, описывающих состояние действия на момент его уничтожения.
Сохраненные данные, которые система использует для восстановления предыдущего состояния, называются состоянием экземпляра и представляют собой набор пар ключ-значение, хранящихся в Bundleобъекте. По умолчанию система использует Bundleсостояние экземпляра для сохранения информации о каждом Viewобъекте в макете вашей активности (например, текстовое значение, введенное в EditTextвиджет). Итак, если ваш экземпляр активности уничтожен и воссоздан, состояние макета восстанавливается до его предыдущего состояния без необходимости кода. Однако у вашей активности может быть дополнительная информация о состоянии, которую вы хотели бы восстановить, например переменные-члены, которые отслеживают ход выполнения пользователем действия.
Примечание. Чтобы система Android восстанавливала состояние представлений в вашей активности, каждое представление должно иметь уникальный идентификатор, предоставляемый android:id атрибутом.
Объект Bundle не подходит для хранения более чем тривиального объема данных, поскольку он требует сериализации в основном потоке и потребляет память системного процесса. Чтобы сохранить больше, чем очень небольшой объем данных, вы должны использовать комбинированный подход к сохранению данных, используя постоянное локальное хранилище, onSaveInstanceState() метод и класс, как описано в разделе Сохранение состояний пользовательского интерфейса . ViewModel
Сохраняйте простое и облегченное состояние UI с помощью onSaveInstanceState( ) .
Когда ваша активность начинает останавливаться, система вызывает onSaveInstanceState() метод, чтобы ваша активность могла сохранить информацию о состоянии в пакет состояния экземпляра. Реализация этого метода по умолчанию сохраняет временную информацию о состоянии иерархии представлений действия, такую как текст в EditText виджете или положение прокрутки ListView виджета.
Чтобы сохранить дополнительную информацию о состоянии экземпляра для вашего действия, вы должны переопределить onSaveInstanceState() и добавить пары ключ-значение к Bundle объекту, который сохраняется в случае неожиданного уничтожения вашего действия. Если вы переопределяете onSaveInstanceState(), вы должны вызвать реализацию суперкласса, если вы хотите, чтобы реализация по умолчанию сохраняла состояние иерархии представлений. Например:
//Kotlin
override fun onSaveInstanceState(outState: Bundle?) {
// Save the user's current game state
outState?.run {
putInt(STATE_SCORE, currentScore)
putInt(STATE_LEVEL, currentLevel)
}
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(outState)
companion object {
val STATE_SCORE = "playerScore"
val STATE_LEVEL = "playerLevel"
}
Примечание: onSaveInstanceState() не вызывается, когда пользователь явно закрывает activity или в других случаях, когда вызывается finish().
Чтобы сохранить постоянные данные, такие как пользовательские настройки или данные для базы данных, вы должны использовать соответствующие возможности, когда ваша деятельность находится на переднем плане. Если такой возможности не возникает, следует сохранить такие данные во время onStop() метода.
Восстановить состояние UI activity, используя сохраненное состояние экземпляра
Когда ваша активность воссоздается после того, как она была ранее уничтожена, вы можете восстановить сохраненное состояние экземпляра из того Bundle, что система передает вашей активности. Оба метода обратного вызова onCreate()и получают одно и то же , содержащее информацию о состоянии экземпляра. onRestoreInstanceState()Bundle
Поскольку метод onCreate() вызывается независимо от того, создает ли система новый экземпляр вашей активности или воссоздает предыдущий, вы должны проверить, является ли состояние Bundle нулевым, прежде чем пытаться его прочитать. Если он равен нулю, то система создает новый экземпляр действия, а не восстанавливает предыдущий, который был уничтожен.
Например, следующий фрагмент кода показывает, как можно восстановить некоторые данные состояния в onCreate():
//Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
with(savedInstanceState) {
// Restore value of members from saved state
currentScore = getInt(STATE_SCORE)
currentLevel = getInt(STATE_LEVEL)
}
} else {
// Probably initialize members with default values for a new instance
}
// ...
}
Вместо восстановления состояния во время onCreate() вы можете выбрать реализацию onRestoreInstanceState(), которую система вызывает после метода onStart(). Система вызывается onRestoreInstanceState() только в том случае, если есть сохраненное состояние для восстановления, поэтому вам не нужно проверять, является ли значение Bundle = null:
//Kotlin
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState)
// Restore state members from saved instance
savedInstanceState?.run {
currentScore = getInt(STATE_SCORE)
currentLevel = getInt(STATE_LEVEL)
}
}
Внимание! Всегда вызывайте реализацию суперкласса onRestoreInstanceState(), чтобы реализация по умолчанию могла восстановить состояние иерархии представлений.
Навигация между activity
Приложение может входить в действие и выходить из него, возможно, много раз за время существования приложения. Например, пользователь может нажать кнопку «Назад» на устройстве, или для действия может потребоваться запуск другого действия. В этом разделе рассматриваются темы, которые вам необходимо знать для реализации успешных переходов активности. Эти темы включают запуск действия из другого действия, сохранение состояния действия и восстановление состояния действия.
Старт одного activity из другого
В какой-то момент операции часто требуется запустить другую операцию. Такая необходимость возникает, например, когда приложению необходимо перейти с текущего экрана на новый.
В зависимости от того, хочет ли ваша активность получить результат от новой активности, которую она собирается запустить, вы запускаете новую активность, используя метод startActivity() или startActivityForResult() . В любом случае вы передаете Intent объект.
Объект Intent указывает либо конкретное действие, которое вы хотите запустить, либо описывает тип действия, которое вы хотите выполнить (и система выбирает для вас подходящее действие, которое может быть даже из другого приложения). Объект Intent также может содержать небольшие объемы данных, которые будут использоваться запускаемой активностью. Дополнительные сведения о Intent классе см. в разделе Намерения и фильтры намерений .
startActivity()
Если вновь запущенному действию не нужно возвращать результат, текущее действие может запустить его, вызвав startActivity() метод.
При работе в собственном приложении вам часто нужно просто запустить известное действие. Например, в следующем фрагменте кода показано, как запустить действие с именем SignInActivity.
//Лщедшт
val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)
Вашему приложению также может понадобиться выполнить какое-либо действие, например отправить электронное письмо, текстовое сообщение или обновить статус, используя данные из вашей активности. В этом случае ваше приложение может не иметь собственных действий для выполнения таких действий, поэтому вместо этого вы можете использовать действия, предоставляемые другими приложениями на устройстве, которые могут выполнять действия за вас. Вот где намерения действительно ценны: вы можете создать намерение, описывающее действие, которое вы хотите выполнить, и система запускает соответствующее действие из другого приложения. Если есть несколько действий, которые могут обработать намерение, пользователь может выбрать, какое из них использовать. Например, если вы хотите разрешить пользователю отправлять сообщение электронной почты, вы можете создать следующее намерение:
//Kotlin
val intent = Intent(Intent.ACTION_SEND).apply {
putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)
EXTRA_EMAIL дополнительно к intent добавлен строковый массив адресов электронной почты, на которые должно быть отправлено электронное письмо. Когда приложение электронной почты отвечает на это намерение, оно считывает массив строк, предоставленный в дополнении, и помещает их в поле «Кому» формы составления электронной почты. В этой ситуации начинается активность почтового приложения, и когда пользователь закончит, ваша активность возобновится.
startActivityForResult( )
Иногда вы хотите получить результат от действия, когда оно завершится. Например, вы можете запустить действие, позволяющее пользователю выбрать человека из списка контактов; когда он заканчивается, он возвращает человека, который был выбран. Для этого вы вызываете startActivityForResult(Intent, int) метод, где целочисленный параметр идентифицирует вызов. Этот идентификатор предназначен для устранения неоднозначности между несколькими вызовами startActivityForResult(Intent, int) из одного и того же действия. Это не глобальный идентификатор, и он не конфликтует с другими приложениями или действиями. Результат возвращается с помощью вашего onActivityResult(int, int, Intent) метода.
Когда дочерняя активность завершается, она может вызвать setResult(int)возврат данных своему родителю. Дочернее действие всегда должно предоставлять код результата, который может быть стандартным результатом RESULT_CANCELED, RESULT_OKили любыми пользовательскими значениями, начинающимися с RESULT_FIRST_USER. Кроме того, дочерняя активность может дополнительно возвращать Intent объект, содержащий любые дополнительные данные, которые она хочет. Родительское действие использует onActivityResult(int, int, Intent) метод вместе с целочисленным идентификатором, изначально предоставленным родительским действием, для получения информации.
Если дочерняя активность по какой-либо причине завершается сбоем, например, из-за сбоя, родительская активность получает результат с кодом RESULT_CANCELED.
//Kotlin
class MyActivity : Activity() {
// ...
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
// When the user center presses, let them pick a contact.
startActivityForResult(
Intent(Intent.ACTION_PICK,Uri.parse("content://contacts")),
PICK_CONTACT_REQUEST)
return true
}
return false
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
when (requestCode) {
PICK_CONTACT_REQUEST ->
if (resultCode == RESULT_OK) {
startActivity(Intent(Intent.ACTION_VIEW, intent?.data))
}
}
}
companion object {
internal val PICK_CONTACT_REQUEST = 0
}
}
Координация activity
Когда одно действие запускает другое, они оба испытывают переходы жизненного цикла. Первая активность перестает работать и переходит в состояние Paused или Stopped, в то время как другая активность создается. В случае, если эти действия совместно используют данные, сохраненные на диске или в другом месте, важно понимать, что первое действие не останавливается полностью до того, как будет создано второе. Скорее, процесс запуска второго перекрывается с процессом остановки первого.
Порядок обратных вызовов жизненного цикла четко определен, особенно когда два действия находятся в одном процессе (приложении) и одно запускает другое. Вот порядок операций, которые происходят, когда activity "A" запускает activity "B":
- Activity "B" методы onCreate(), onStart(), и onResume() выполняются последовательно. (activity "B" теперь находится в фокусе пользователя.)
Эта предсказуемая последовательность обратных вызовов жизненного цикла позволяет управлять переходом информации от одного действия к другому.
источник: https://developer.android.com/guide/components/activities/activity-lifecycle#kotlin
#android developments #android studio #kotlin #activity