Android activity lifecycle

Android Pro Kotlin. Глава 3. Активности Android. Часть 2

Оглавление

Android Pro Kotlin. Глава 3. Активности Android. Часть 1

Системные фильтры намерений

Жизненный цикл Активности Android

Сохраняем состояние активности между перезапусками

Системные фильтры намерений

Системные приложения, т.е. приложения которые уже были установлены на Вашем приложении до момента покупки, имеют свои фильтры намерений, которые Вы можете использовать в своем приложении, для их вызова. К сожалению, не всегда можно сразу отгадать, какой неявный запрос намерения необходимо использовать для их вызова. В случае если нет возможности найти документацию в интернете, единственный возможный вариант – это реверс инжиниринг системных файлов APK . Но начиная с  API 26, Вы можете найти всю информацию на официальном сайте с Android документацией в разделе “The System Intent Filters“.

Рассмотрим пример. Например Вы хотите реализовать функционал отправки электронного письма и чтобы не тратить месяцы на внедрение функционала, который будет весьма редко использоваться Вашими пользователями, отправим намерение системному почтовому приложению с действием по отправке электронного письма. Если посмотреть на таблицу вариантов фильтра намерений для системного приложения PrebuiltGmail, можно немного запутаться. Интерфейс общего назначения не должен быть слишком запутанным и иметь много входных параметров. Во вторых надо посмотреть на имена действий, чтобы найти то, которое нам подходит больше всего. Многообещающим кандидатом является действие “SEND_TO” – ему необходимо передать всего лишь параметр “mailto:“. И это именно тот параметр, который нам нужен. Используя URI вида "mailto:...” можно указывать имена получаталей, имена получателей копии или скрытых получателей, тему и даже тело письма. Однако Вы также можете использовать URI типа “mailto:timur@it-notepad.com” и добавлять получателей, тело и тему письма через дополнительные поля. Таким образом можно отправить письмо, используя почтовые приложения, установленные на устройстве. Например:

val emailIntent:Intent = Intent(Intent.ACTION_SENDTO,      
Uri.fromParts("mailto","abc@gmail.com", null))  
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Subject")  
emailIntent.putExtra(Intent.EXTRA_TEXT, "Body")  
startActivity(Intent.createChooser(emailIntent, "Send email..."))  
// or startActivity(emailIntent) if you want to use  
// the standard chooser (or none, if there is only  
// one possible receiver).

Осторожно То, как именно обрабатывается URI сторонним приложением, остается на усмотрение установленного приложения. Плохо спроектированная программа может вообще не позволять указывать данные заголовка электронной почты.  Для того, чтобы быть уверенным в правильности обработки входящего намерения, Вы можете например, указывать тему, тело(в применении к разговору о приложении для электронной почты) в качестве дополнительных полей намерения.


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

Активности имеют жизненный цикл и в отличие от традиционных настольных приложений, активность может быть преднамеренно уничтожаться ОС Android, когда посчитает это нужным. Таким образом Вам, как разработчику, необходимо предусмотреть эти случаи, если Вы хотите чтобы Ваше приложение было качественным и стабильным. Активности имеют следующие состояния:

  • Created – Создано. Это первое состояние в жизненном цикле активности. Не важно, как активность была запущена – пользователем или вообще другим компонентом приложения, если политика безопасности позволяет – происходит создание активности. Кроме того, активность создается заново также при повороте экрана и UI должен быть перерисован заново под новые параметры экрана. При этом вызывается метод обратного вызова onCreate(). Вы обязательно должны реализовать этот обратный метод, так как именно в нем создается графический интерфейс. Также Вы можете использовать метод onCreate() для запуска или подключения к сервисам или для получения данных из поставщика контента. И Вы также можете в этом методе реализовывать API для подготовки к проигрыванию музыки, работе с камерой или для других действий, для которых предназначено Ваше приложение. А также можно инициализировать базу данных или другое хранилище данных, необходимое Вашему приложению.
  • ЗапущеноStarted. После того, как активность создана, а также в случае перезапуска приложения после того как приложение было остановлено, активность переходит в состояние Запущено. Состоянию – запущено соответствует обратный вызов метода onStart(). В этот методе лучше всего запускать широковещательные приемники, сервисы и восстанавливать работу всех служб и сервисов, которые были остановлены при переходе в состояние Остановлено(см. далее).
  • ВозобновленоResumed. Активность уже создана и запущена, и перед тем как стать видимой пользователем она проходит процесс возобновления. Во время этого процесса вызывается обратный вызов onResume()
  • Выполняется – Running. Активность видна и пользователь может с ней работать. Это состояние идет сразу же по окончании выполнения обратного вызова onResume()
  • Пауза – Paused. Активность теряет фокус, но все еще частично видна. Активность теряет фокус когда, например, пользователь нажимает кнопку Назад или Недавние. Активность может продолжать обновлять UI или воспроизводить звук. Однако в большинстве случаев активность переходит в состояние остановки(см. далее). Этому состоянию соответствует обратный вызов onPause(). После активность либо переходит в состояние Остановлено, либо в состояние Возобновлено.
  • ОстановленоStopped. Активность становится невидимой пользователю. Позже она может быть либо перезапущена, либо уже удалена и вычеркнута из списка активных процессов. Этому состоянию соответствует обратный вызов onStop(). В этом обратном вызове обычно останавливаются все службы, запущенные в методу onStart().
  • УничтоженоDestroyed. Активность удалена. В этот момент вызывается обратный вызов onDestroy(). Хотя Вы можете здесь освободить ресурсы, официальная документация гласит, что этот обратный вызов не всегда может вызываться при уничтожении активности.
  • Завершено Shut down. активность не видна и ничего не обрабатывает. Тем не менее приложение может еще выполняться, т.к. в нем могут выполняться другие компоненты – сервисы или другие активности например.

Возможные состояния активности и переходы между ними приведены в таблице 3.1

 

От состояния К состоянию Описание Обратный вызов
Завершено Создано Активность вызывается первый раз или после уничтожения onCreate() – подготовка UI и старт сервисов
Создано Запущено Активность запускается после создания onStart() – здесь можно запускать службы, которые нужны только в том случае, когда активность видна
Запущено Возобновлено Состояние Возобновлено следует автоматически после состояния Запущена onResume()
Возобновлено Работает Состояние Работает автоматически следует за состоянием Возобновлено Активность видна и функционирует для работы с пользователем
Работает Пауза Активность теряет фокус, потому что пользователь нажал кнопку Назад или Недавние onPause()
Пауза Возобновлено Активность не остановлена и пользователь возвращается к активности onResume()
Пауза Остановлено Активность больше не видна пользователю, например потому что запускается другая активность onStop() Вы можете остановить сервисы, которые больше не нужны если активность больше не видна.
Остановлено Запущено Остановленная активность запущена снова onStart() Вы можете снова запустить сервисы, которые нужны если активность становится видимой.
Остановлено Уничтожено Остановленная активность удалена onDestroy() Освободите все ресурсы, выполните очистку и остановите сервисы, которые были запущены в методу onCreate()
Таблица 3.1 Переходы между состояниями активности
Android activity lifecycle
Рис. 3.1 Жизненный цикл Android активности

Сохраняем состояние активности между перезапусками

Мы уже вскользь упоминали эту тему раньше, про сохранение состояние активности между перезапусками. И не важно из за чего это происходит – из за поворота устройства или из за принудительной остановки активности –  ОС Android. Здесь мы рассказываем подробнее про этот процесс. 

Глядя на жизненный цикл активности – мы видим, что активность уничтожается после выполнения метода onStop. В жизненном цикле активности есть еще 2 метода, о которых мы не упомянули –  onSaveInstanceState() и onRestoreInstanceState(). Они вызываются каждый раз, когда Android решает, что активность должна быть сохранена или восстановлена. Это не то же самое что вызовы onStart() и onStop() – потому что в них не всегда имеет смысл сохранять состояние активности. Например если активность не была уничтожена, а просто приостановлена, состояние будет сохранено, и методы onSaveInstanceState() и onRestoreInstanceState() вызываться не будут. 

Что касается перезапуска активности – Android нам в этом плане здорово помогает – стандартные реализации вызовов onSaveInstanceState() и onRestoreInstanceState() сохраняют и восстанавливают элементы пользовательского интерфейса, имеющие ID идентификатор. Если это все, что Вам нужно, больше ни о чем беспокоиться не надо. Если у Вас сложная активность, содержащая поля, ползунки и прогресс – здесь уже необходимо самому заниматься сохранением значений UI. В этом случае Вам необходимо переопределить методы обратного вызова onSaveInstanceState() и onRestoreInstanceState(). И убедиться что Вы вызываете в них одноименные методы суперкласса:

override fun onSaveInstanceState(outState:Bundle?) {    
    super.onSaveInstanceState(outState)    
    // add your own data to the Bundle here...    
    // you can use one of the put* methods here    
    // or write your own Parcelable types
}

override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    super.onRestoreInstanceState(savedInstanceState)
    // restore your own data from the Bundle here...
    // use one of the get* methods here
}

Обратите внимание на тот факт, что сохраненное состояние также передается обратному методу onCreate(), так что это уже ваше решение, где вы хотите восстанавливать данные – в методе onRestoreInstanceState() или onCreate().

Не во всех ситуация механизм сохранения состояний может Вам подойти. Например, Вы не можете сохранить данные, если после вызова onStop() последует вызов onDestroy(). В этом случае метод onSaveInstanceState() не будет вызван.  Если Вы хотите сохранить состояние при уничтожении приложения, Вы можете реализовать сохранение данных в методе onDestroy(), записав все данные в хранилище настроек или в базу данных(поставщик контента), и затем прочитать их снова в метода обратного вызова onCreate(). См. раздел Базы данных, глава 8. 

 
 
 

 
 
 

Leave a Reply

Please disable your adblocker or whitelist this site!