Activity — по сути, это экран, который видит пользователь. Именно здесь происходит взаимодействие с пользователем: показываем ему информацию, обрабатываем ввод и т.п. В активити у нас располагаются всякие элементы: кнопки, фрагменты, изображения и другие различные View. Из-за всего этого, объем памяти, потребляемый активити, может существенно увеличиваться.
Когда пользователь перемещается между экранами, экземпляры активити образуют стек. Положение в стеке определяет состояние каждого экземпляра. Состояние может быть:
- Активная — активити на переднем плане, которая полностью видна.
- Приостановлена — активити отображается частично.
- Остановлена — активити не видна. Например, пользователь перешел на другой экран.
- Неактивна — активити удалена.
Это состояние определяет системный приоритет приложения, а это влияет напрямую на возможность завершения приложения и на планирование выполнения потоков.
Жизненным циклом активити (и других) и взаимодействием компонентов управляет прикладная среда. Она же его определяет. И она же уведомляет нас о том, какая сейчас стадия, чтобы мы смогли как-то отреагировать.
В самой активити и всех его подклассах есть набор методов (callback), которые можно использовать при изменении состояния активити. Эти методы можно переопределить. Зачем они нужны? Например, чтобы мы могли менять какое-то поведение, если, например, активити не видима. Когда наше приложение свернуто или пользователь отвлекся на звонок и приложение не видно, то было бы логично в этот момент поставить видео на паузу, остановить анимацию и т.п. Вот те методы как раз ловят такие моменты и там можно прописать, что нужно сделать. Звучит удобно.
Как выглядит жизненный цикл:
Состояния жизненного цикла. Они общие для фрагмента и активити:
- Initialized — Стартовое состояние, когда создается новая активити. Отсюда сразу же переходит ко второму состоянию.
- Created — Активити создана, но все еще не видима и пользователь никак не может взаимодействовать с ней.
- Started — Активити уже видна, но все еще не в фокусе.
- Resumed — Все видно и в фокусе. Полностью рабочее и пользователь может взаимодействовать.
- Destroyed — Активити уничтожена. Теперь она может быть удалена из памяти в любой момент, поэтому на нее нельзя ссылаться и как-то взаимодействовать.
И сами методы:
onCreate — Вызывается первым, когда активити стартует. Появление этого метода означает, что активити создана и проинициализирована. Он вызывается всего один раз за весь жизненный цикл. Тут мы можем проинициализировать какой-то ui, переменные и сделать что-то еще, что должно делаться только один раз за весь жизненный цикл. Помните, что тут активити еще не видна и не в фокусе.
onStart — метод срабатывает, когда активити вот-вот станет видимой. Этот метод срабатывает несколько раз. Например, когда пользователь переходит на другой экран, а потом возвращается. Активити все еще не в фокусе и не видима. Тут мы можем запускать любые штуки, которые должны запускаться, когда активити становится видима. Например, анимация.
onResume — срабатывает, когда активити в фокусе и пользователь может с ней взаимодействовать. Соответственно, тут мы запускаем что-то, что должно работать, когда появляется фокус. Как вариант: всё та же анимация.
onPause — парный метод для onResume. Вызывается, когда теряется фокус. Например, появился какой-то диалог или системное сообщение. Сейчас пользователь не может взаимодействовать с активити. Тут можно что-то останавливать, что не должно работать, когда нет фокуса. ВАЖНО: если что-то делаем тут, то оно должно быть моментальным, потому что следующая активити не откроется, пока не завершится метод. Будет неприятно, что вы нажимаете кнопку для перехода — должен открыться экран — а приложение думает несколько секунд, потому что вы сделали какое-то сохранение данных в onPause + кучу остановок.
onStop — парный метод для onStart. Вызывается, когда активити больше не видна. Тут останавливаем всё, что не должно выполняться, когда активити не на экране. Например, останавливаем анимацию, видео, и любую логику для ui. Не нужно тратить ресурсы впустую, когда пользователь не смотрит. Плюс помним про фоновые ограничения. Также тут можем сохранить какие-то данные, если надо.
onDestroy — парный метод для onCreate. Вызывается один раз, когда активити полностью уничтожена. Например, вы нажали на кнопку назад или вручную вызвали finish(). Это последний шанс удалить и освободить все ресурсы, которые не освобождаются автоматически. Не забывайте про это, а то может привести к утечке памяти. Плюс, логика, которая относится к обновлению UI, после уничтожения активити, может привести к крашу.
Когда переходим в onStop, система использует onSaveInstanceState, чтобы сохранить состояние приложение, если придется его убить. Например, если мы свернули приложение, а системе пришлось убить процесс, то когда мы откроем бэкстек с приложениями, то убитое приложение все равно будет видно. Система его самостоятельно постарается восстановить. Но, onSaveInstanceState не вызывается, если мы вызываем finish() и нажимаем назад. Потому что активити уничтожена. Сохранять нечего.
Жизненный цикл активити завершается, когда пользователь возвращается к предыдущему экрану или когда активити вызывает метод finish().
Какие вопросы тут можно задать:
- Когда в activity вызывается finish(), какие методы жизненного цикла вызываются?
- Что будет, если мы вызовем finish() в методе, а чуть дальше напишем что-то еще?
- А есть еще какие-то методы, которые вызываются только один раз или только onCreate?
- Что такое "Утечка памяти?"
- А давай поподробней про onSaveInstanceState. Тут мы сохраняем, а как и когда достаем?
- А про какие менее популярные callbacks ты знаешь?
Не стесняйтесь писать свои вопросы, которые могут появиться. :)
Дубль статей в телеграмме — https://t.me/android_junior
Мой твиттер в телеграмме — https://t.me/android_junior_notes