Android Kotlin Fundamentals 04.1: Жизненные циклы и ведение журнала

Эта кодовая лаборатория является частью курса Android Kotlin Fundamentals. Вы получите максимальную отдачу от этого курса, если будете последовательно работать с лабораториями кода. Все кодовые лаборатории курса перечислены на целевой странице кодовых лабораторий Android Kotlin Fundamentals .

Введение

В этой лабораторной работе вы узнаете о фундаментальной части Android: жизненном цикле действий и фрагментов. Жизненный цикл действия — это набор состояний, в которых может находиться действие в течение своего жизненного цикла. Жизненный цикл продолжается с момента первоначального создания действия до момента его уничтожения и восстановления системой ресурсов этого действия. По мере того, как пользователь перемещается между действиями в вашем приложении (а также в ваше приложение и из него), каждое из этих действий переходит из одного состояния в жизненный цикл действия.

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

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

Что вы уже должны знать

  • Что такое активность и как ее создать в приложении.
  • Что делает метод onCreate() действия и какие операции выполняются в этом методе.
  • Как создавать макеты XML для своей деятельности и как обновлять макет во время выполнения.

Что вы узнаете

  • Как распечатать информацию журнала в Logcat (иногда называемый консолью Android или монитором Android).
  • Основы жизненных циклов Activity и Fragment , а также обратные вызовы, которые вызываются, когда действие перемещается между состояниями.
  • Как переопределить методы обратного вызова жизненного цикла для выполнения операций в разное время жизненного цикла активности.
  • Как использовать библиотеку Timber для ведения журнала в вашем приложении.

Что ты будешь делать

  • Измените начальное приложение под названием DessertClicker, чтобы добавить информацию журнала, которая отображается в файле Logcat.
  • Переопределите методы обратного вызова жизненного цикла и зарегистрируйте изменения в состоянии активности.
  • Запустите приложение и обратите внимание на информацию журнала, которая появляется при запуске, остановке и возобновлении действия.
  • Измените приложение, чтобы использовать библиотеку Timber .
  • Добавьте ведение журнала в приложение AndroidTrivia и отслеживайте изменения состояний фрагментов.

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

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

У каждой активности и каждого фрагмента есть так называемый жизненный цикл . Это намек на жизненные циклы животных, такие как жизненный цикл этой бабочки — различные состояния бабочки показывают ее рост от рождения до полностью сформированной взрослой жизни и до смерти.

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

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

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

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

Шаг 1. Изучите метод onCreate() и добавьте ведение журнала

Чтобы понять, что происходит с жизненным циклом Android, полезно знать, когда вызываются различные методы жизненного цикла. Это поможет вам определить, где что-то идет не так в DessertClicker.

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

  1. Загрузите стартовое приложение DessertClicker и откройте его в Android Studio.
  2. Скомпилируйте и запустите приложение, несколько раз нажмите на изображение десерта. Обратите внимание, как меняется значение « Продано десертов» и общая сумма в долларах.
  3. Откройте MainActivity.kt и проверьте метод onCreate() для этого действия.
override fun onCreate(savedInstanceState: Bundle?) {
...
}

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

Метод жизненного цикла onCreate() вызывается один раз сразу после инициализации активности (когда в памяти создается новый объект Activity ). После onCreate() действие считается созданным .

  1. В onCreate() сразу после вызова super.onCreate() добавьте следующую строку. При необходимости импортируйте класс Log . (Нажмите Alt+Enter или Option+Enter на Mac и выберите « Импорт ».)
Log.i("MainActivity", "onCreate Called")

Класс Log записывает сообщения в Logcat. Эта команда состоит из трех частей:

  • Серьезность сообщения журнала, то есть насколько важно сообщение. В этом случае метод Log.i() выводит информационное сообщение. Другие методы класса Log включают Log.e() для ошибок или Log.w() для предупреждений.
  • Тег журнала, в данном случае "MainActivity" . Тег представляет собой строку, которая упрощает поиск сообщений журнала в Logcat. Тег обычно представляет собой имя класса.
  • Фактическое сообщение журнала, короткая строка, в данном случае "onCreate called" .
  1. Скомпилируйте и запустите приложение DessertClicker. Вы не видите никаких различий в поведении приложения, когда вы нажимаете на десерт. В Android Studio внизу экрана щелкните вкладку Logcat .



    Logcat — это консоль для регистрации сообщений. Здесь отображаются сообщения от Android о вашем приложении, включая сообщения, которые вы явно отправляете в журнал с помощью Log.i() или других методов класса Log .
  2. На панели Logcat введите I/MainActivity в поле поиска.


    Logcat может содержать много сообщений, большинство из которых бесполезны для вас. Вы можете фильтровать записи Logcat разными способами, но поиск — самый простой. Поскольку вы использовали MainActivity в качестве тега журнала в своем коде, вы можете использовать этот тег для фильтрации журнала. Добавление I/ в начале означает, что это информационное сообщение, созданное Log.i() .

    Ваше сообщение журнала включает дату и время, имя пакета ( com.example.android.dessertclicker ), ваш тег журнала (с I/ в начале) и фактическое сообщение. Поскольку это сообщение появляется в журнале, вы знаете, что onCreate() был выполнен.

Шаг 2: Реализуйте метод onStart()

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

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

  1. В Android Studio при открытом MainActivity.kt выберите Code > Override Methods или нажмите Control+o . Появится диалоговое окно с огромным списком всех методов, которые вы можете переопределить в этом классе.
  2. Начните вводить onStart для поиска нужного метода. Чтобы перейти к следующему подходящему элементу, используйте стрелку вниз. Выберите onStart() из списка и нажмите OK , чтобы вставить стандартный код переопределения. Код выглядит следующим образом:
override fun onStart() {
   super.onStart()
}
  1. Внутри onStart() добавьте сообщение журнала:
override fun onStart() {
   super.onStart()

   Log.i("MainActivity", "onStart Called")
}
  1. Скомпилируйте и запустите приложение DessertClicker и откройте панель Logcat . Введите I/MainActivity в поле поиска, чтобы отфильтровать журнал. Обратите внимание, что onCreate() и onStart() вызывались один за другим, и ваша активность видна на экране.
  2. Нажмите кнопку «Домой» на устройстве, а затем используйте экран «Недавние», чтобы вернуться к действию. Обратите внимание, что действие возобновляется с того места, где оно было остановлено, со всеми теми же значениями, и что onStart() регистрируется во второй раз в Logcat. Заметьте также, что метод onCreate() обычно больше не вызывается.

В этой задаче вы модифицируете свое приложение, чтобы оно использовало популярную библиотеку журналов под названием Timber . Timber имеет несколько преимуществ перед встроенным классом Android Log . В частности, библиотека Timber :

  • Создает для вас тег журнала на основе имени класса.
  • Помогает избежать отображения журналов в окончательной версии вашего приложения для Android.
  • Позволяет интегрироваться с библиотеками отчетов о сбоях.

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

Шаг 1. Добавьте древесину в Gradle

  1. Перейдите по этой ссылке на проект Timber на GitHub и скопируйте строку кода под заголовком « Загрузка », которая начинается со слова « implementation ». Строка кода будет выглядеть примерно так, хотя номер версии может быть другим.
implementation 'com.jakewharton.timber:timber:4.7.1'
  1. В Android Studio в представлении Project: Android разверните Gradle Scripts и откройте файл build.gradle (Module: app) .
  2. В раздел зависимостей вставьте скопированную строку кода.
dependencies {
   ...
   implementation 'com.jakewharton.timber:timber:4.7.1'
}
  1. Щелкните ссылку « Синхронизировать сейчас» в правом верхнем углу Android Studio, чтобы перестроить Gradle. Сборка должна выполняться без ошибок.

Шаг 2: Создайте класс приложения и инициализируйте Timber

На этом этапе вы создаете класс Application . Application — это базовый класс, который содержит глобальное состояние приложения для всего приложения. Это также основной объект, который операционная система использует для взаимодействия с вашим приложением. Существует класс Application по умолчанию, который Android использует, если вы его не укажете, поэтому всегда есть объект Application , созданный для вашего приложения, и вам не нужно делать ничего особенного для его создания.

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

После создания класса Application вам необходимо указать класс в манифесте Android.

  1. В dessertclicker создайте новый класс Kotlin с именем ClickerApplication . Для этого разверните app > java и щелкните правой кнопкой мыши com.example.android.dessertclicker . Выберите « Создать» > «Файл/класс Kotlin» .
  2. Назовите класс ClickerApplication и задайте для Kind значение Class . Нажмите ОК .

Android Studio создает новый класс ClickerApplication и открывает его в редакторе кода. Код выглядит следующим образом:

package com.example.android.dessertclicker

class ClickerApplication {
}
  1. Измените определение класса, чтобы оно было подклассом Application , и при необходимости импортируйте класс Application .
class ClickerApplication : Application() {
  1. Чтобы переопределить метод onCreate() , выберите « Код» > «Переопределить методы» или нажмите Control+o .
class ClickerApplication : Application() {
   override fun onCreate() {
       super.onCreate()
   }
}
  1. Внутри этого onCreate() инициализируйте библиотеку Timber :
override fun onCreate() {
    super.onCreate()

    Timber.plant(Timber.DebugTree())
}

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

  1. Откройте файл AndroidManifest.xml .
  2. В верхней части элемента <application> добавьте новый атрибут для класса ClickerApplication , чтобы Android знал, что нужно использовать ваш класс Application вместо класса по умолчанию.
<application
   android:name=".ClickerApplication"
...

Шаг 3. Добавьте отчеты журнала Timber

На этом шаге вы изменяете свои Log.i() для использования Timber , затем реализуете ведение журнала для всех других методов жизненного цикла.

  1. Откройте MainActivity и перейдите к onCreate() . Замените Log.i() на Timber.i() и удалите тег журнала.
Timber.i("onCreate called")

Как и класс Log , Timber также использует метод i() для информационных сообщений. Обратите внимание, что с Timber вам не нужно добавлять тег журнала; Timber автоматически использует имя класса в качестве тега журнала.

  1. Точно так же измените вызов Log в onStart() :
override fun onStart() {
   super.onStart()

   Timber.i("onStart Called")
}
  1. Скомпилируйте и запустите приложение DessertClicker и откройте Logcat. Обратите внимание, что вы по-прежнему видите те же сообщения журнала для onCreate() и onStart() , только теперь эти сообщения генерирует Timber , а не класс Log .
  2. Переопределите остальные методы жизненного цикла в MainActivity и добавьте операторы журнала Timber для каждого из них. Вот код:
override fun onResume() {
   super.onResume()
   Timber.i("onResume Called")
}

override fun onPause() {
   super.onPause()
   Timber.i("onPause Called")
}

override fun onStop() {
   super.onStop()
   Timber.i("onStop Called")
}

override fun onDestroy() {
   super.onDestroy()
   Timber.i("onDestroy Called")
}

override fun onRestart() {
   super.onRestart()
   Timber.i("onRestart Called")
}
  1. Скомпилируйте и снова запустите DessertClicker и проверьте Logcat. На этот раз обратите внимание, что в дополнение к onCreate() и onStart() есть сообщение журнала для обратного вызова жизненного цикла onResume() .

Когда действие начинается с нуля, вы видите, что все три из этих обратных вызовов жизненного цикла вызываются по порядку:

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

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

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

Вариант использования 1: открытие и закрытие активности

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

  1. Скомпилируйте и запустите приложение DessertClicker, если оно еще не запущено. Как вы видели, onCreate() , onStart() и onResume() вызываются при первом запуске действия.
  2. Нажмите на кекс несколько раз.
  3. Нажмите кнопку «Назад» на устройстве. Обратите внимание, что в Logcat onPause() , onStop() и onDestroy() вызываются именно в таком порядке.

    В этом случае использование кнопки «Назад» приводит к полному закрытию действия (и приложения). Выполнение метода onDestroy() означает, что активность была полностью остановлена ​​и может быть удалена сборщиком мусора. Сборка мусора относится к автоматической очистке объектов, которые вы больше не будете использовать. После onDestroy() ОС знает, что эти ресурсы можно сбросить, и начинает очищать эту память.

    Ваша активность также может быть полностью закрыта, если ваш код вручную вызывает метод finish() активности или если пользователь принудительно завершает работу приложения. (Например, пользователь может принудительно закрыть приложение на экране «Последние», щелкнув X в углу окна.) Система Android также может отключить вашу активность самостоятельно, если ваше приложение не отображалось на экране в течение долго. Android делает это для экономии заряда батареи и позволяет другим приложениям использовать ресурсы вашего приложения.
  4. Используйте экран недавних, чтобы вернуться в приложение. Вот Логкат:


    Активность была уничтожена на предыдущем шаге, поэтому, когда вы вернетесь в приложение, Android запустит новую активность и onCreate() , onStart() и onResume() . Обратите внимание, что никакая статистика DessertClicker из предыдущего действия не была сохранена.

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

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

Вариант использования 2: переход от действия и обратно к нему

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

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

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

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

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

Для этого также есть причина производительности. Допустим, пользователь открыл 20 приложений, в которых используется физическое моделирование с интенсивным использованием ЦП. Если действия этих приложений не отображаются на экране, но они все еще выполняют тяжелые вычисления рендеринга в фоновом режиме, это снизит производительность всего телефона.

На этом этапе вы просматриваете жизненный цикл активности, когда приложение переходит в фоновый режим и снова возвращается на передний план.

  1. Запустив приложение DessertClicker, нажмите несколько раз на кекс.
  2. Нажмите кнопку «Домой» на своем устройстве и наблюдайте за Logcat в Android Studio. Возврат на главный экран переводит ваше приложение в фоновый режим, а не закрывает его полностью. Обратите внимание, что onPause() и onStop() вызываются, а onDestroy() — нет.


    Когда onPause() , приложение больше не имеет фокуса. После onStop() приложение больше не отображается на экране. Хотя действие было остановлено, объект Activity все еще находится в памяти в фоновом режиме. Активность не уничтожена. Пользователь может вернуться в приложение, поэтому Android хранит ресурсы вашей активности.
  3. Используйте экран недавних, чтобы вернуться в приложение. Обратите внимание, что в Logcat действие перезапускается с помощью onRestart() и onStart() , а затем возобновляется с помощью onResume() .


    Когда действие возвращается на передний план, метод onCreate() больше не вызывается. Объект активности не был уничтожен, поэтому его не нужно создавать снова. Вместо onCreate() вызывается метод onRestart() . Обратите внимание, что на этот раз, когда действие возвращается на передний план, количество проданных десертов сохраняется.
  4. Запустите хотя бы одно приложение, отличное от DessertClicker, чтобы на экране устройства отображалось несколько приложений.
  5. Поднимите экран недавних событий и откройте другое недавнее действие. Затем вернитесь к недавним приложениям и верните DessertClicker на передний план.

    Обратите внимание, что вы видите здесь те же обратные вызовы в Logcat, что и при нажатии кнопки «Домой». onPause() и onStop() вызываются, когда приложение переходит в фоновый режим, а затем onRestart() , onStart() и onResume() , когда оно возвращается.

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

    А как насчет onRestart() ? Метод onRestart() очень похож на onCreate() . Либо onCreate() , либо onRestart() вызывается до того, как активность станет видимой. Метод onCreate() вызывается только первый раз, после onRestart() . Метод onRestart() — это место для размещения кода, который вы хотите вызывать только в том случае, если ваша активность не запускается в первый раз.

Вариант использования 3: частично скрыть активность

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

Когда приложение переходит в фоновый режим, после onPause() фокус теряется, а после onPause() onStop() больше не отображается.

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

  1. Когда приложение DessertClicker запущено, нажмите кнопку « Поделиться » в правом верхнем углу экрана.




    Активность обмена отображается в нижней половине экрана, но активность по-прежнему видна в верхней половине.
  2. Изучите Logcat и обратите внимание, что вызывалась только onPause() .


    В этом случае onStop() не вызывается, потому что активность все еще частично видна. Но активность не имеет пользовательского фокуса, и пользователь не может с ней взаимодействовать. Действие «поделиться», которое находится на переднем плане, имеет фокус пользователя.

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

    Какой бы код ни выполнялся в onPause() , он блокирует отображение других вещей, поэтому старайтесь, чтобы код в onPause() легковесным. Например, если поступает телефонный звонок, код в onPause() может задержать уведомление о входящем звонке.
  3. Щелкните за пределами диалогового окна общего доступа, чтобы вернуться в приложение, и обратите внимание, что onResume() .

    И onResume() , и onPause() связаны с фокусом. Метод onResume() вызывается, когда активность получает фокус, а onPause() вызывается, когда активность теряет фокус.

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

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

Каждый экран в приложении AndroidTrivia является Fragment .

Для простоты в этой задаче вы используете API ведения журналов Android, а не библиотеку Timber.

  1. Откройте приложение AndroidTrivia из последней лаборатории кода или загрузите код решения AndroidTrivia с GitHub.
  2. Откройте файл TitleFragment.kt . Обратите внимание, что Android Studio может отображать ошибки привязки и неразрешенные ссылки, пока вы не перестроите приложение.
  3. Прокрутите вниз до onCreateView() . Обратите внимание, что именно здесь макет фрагмента раздувается и происходит привязка данных.
  4. Добавьте оператор регистрации в метод onCreateView() между строкой setHasOptionsMenu() и последним вызовом return:
setHasOptionsMenu(true)

Log.i("TitleFragment", "onCreateView called")

return binding.root
  1. Непосредственно под onCreateView() добавьте операторы регистрации для каждого из оставшихся методов жизненного цикла фрагмента. Вот код:
override fun onAttach(context: Context?) {
   super.onAttach(context)
   Log.i("TitleFragment", "onAttach called")
}
override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   Log.i("TitleFragment", "onCreate called")
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
   super.onActivityCreated(savedInstanceState)
   Log.i("TitleFragment", "onActivityCreated called")
}
override fun onStart() {
   super.onStart()
   Log.i("TitleFragment", "onStart called")
}
override fun onResume() {
   super.onResume()
   Log.i("TitleFragment", "onResume called")
}
override fun onPause() {
   super.onPause()
   Log.i("TitleFragment", "onPause called")
}
override fun onStop() {
   super.onStop()
   Log.i("TitleFragment", "onStop called")
}
override fun onDestroyView() {
   super.onDestroyView()
   Log.i("TitleFragment", "onDestroyView called")
}
override fun onDetach() {
   super.onDetach()
   Log.i("TitleFragment", "onDetach called")
}
  1. Скомпилируйте и запустите приложение, а затем откройте Logcat.
  2. Введите I/TitleFragment в поле поиска, чтобы отфильтровать журнал. Когда приложение запустится, Logcat будет выглядеть примерно так, как показано на следующем снимке экрана:

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

  • onAttach() : вызывается, когда фрагмент связан с активностью его владельца.
  • onCreate() : Аналогично onCreate() для активности, onCreate() для фрагмента вызывается для начального создания фрагмента (кроме макета).
  • onCreateView() : вызывается для увеличения макета фрагмента.
  • onActivityCreated() : вызывается, когда onCreate() активности владельца завершена. Ваш фрагмент не сможет получить доступ к активности, пока не будет вызван этот метод.
  • onStart() : вызывается, когда фрагмент становится видимым; параллельно с onStart() активности.
  • onResume() : вызывается, когда фрагмент получает фокус пользователя; параллельно onResume() активности.
  1. Нажмите кнопку « Играть» , чтобы перейти к викторине, и обратите внимание на Logcat.

Открытие следующего фрагмента приводит к закрытию фрагмента заголовка и вызову следующих методов жизненного цикла:

  • onPause() : вызывается, когда фрагмент теряет фокус пользователя; параллельно onPause() активности.
  • onStop() : вызывается, когда фрагмент больше не виден на экране; параллельно onStop() активности.
  • onDestroyView() : вызывается, когда представление фрагмента больше не требуется, для очистки ресурсов, связанных с этим представлением.
  1. В приложении нажмите кнопку «Вверх» (стрелка в левом верхнем углу экрана), чтобы вернуться к фрагменту заголовка.


    На этот раз onAttach() и onCreate() , вероятно, не вызываются для запуска фрагмента. Объект фрагмента все еще существует и все еще привязан к активности своего владельца, поэтому жизненный цикл начинается снова с onCreateView() .
  2. Нажмите кнопку «Домой» на устройстве. Обратите внимание, что в Logcat вызываются только onPause() и onStop() . Это то же поведение, что и для действия: возвращение домой переводит действие и фрагмент на задний план.
  3. Используйте экран недавних, чтобы вернуться в приложение. Как и в случае с активностью, onStart() и onResume() вызываются для возврата фрагмента на передний план.

Проект Android Studio: DessertClickerLogs

Жизненный цикл деятельности

  • Жизненный цикл активности — это набор состояний, через которые мигрирует активность. Жизненный цикл действия начинается, когда действие впервые создается, и заканчивается, когда действие уничтожается.
  • Когда пользователь перемещается между действиями, а также внутри и вне вашего приложения, каждое действие перемещается между состояниями в жизненном цикле действия.
  • Каждое состояние в жизненном цикле активности имеет соответствующий метод обратного вызова, который вы можете переопределить в своем классе Activity . Существует семь методов жизненного цикла:
    onCreate()
    onStart()
    onPause()
    onRestart()
    onResume()
    onStop()
    onDestroy()
  • Чтобы добавить поведение, возникающее при переходе действия в состояние жизненного цикла, переопределите метод обратного вызова состояния.
  • Чтобы добавить методы переопределения каркаса в свои классы в Android Studio, выберите « Код» > «Переопределить методы» или нажмите Control+o .

Ведение журнала с помощью журнала

  • API ведения журналов Android и, в частности, класс Log позволяют писать короткие сообщения, которые отображаются в Logcat в Android Studio.
  • Используйте Log.i() для написания информационного сообщения. Этот метод принимает два аргумента: тег журнала, обычно имя класса, и сообщение журнала, короткую строку.
  • Используйте панель Logcat в Android Studio для просмотра системных журналов, включая написанные вами сообщения.

Ведение журнала с помощью Timber

Timber — это библиотека ведения журналов с рядом преимуществ по сравнению с API ведения журналов Android. В частности, библиотека Timber :

  • Создает для вас тег журнала на основе имени класса.
  • Помогает избежать отображения журналов в окончательной версии вашего приложения для Android.
  • Позволяет интегрироваться с библиотеками отчетов о сбоях.

Чтобы использовать Timber , добавьте его зависимость в файл Gradle и расширьте класс Application для его инициализации:

  • Application — это базовый класс, который содержит глобальное состояние приложения для всего приложения. Существует класс Application по умолчанию, который используется Android, если вы его не укажете. Вы можете создать свой собственный подкласс Application для инициализации библиотек приложения, таких как Timber .
  • Добавьте свой собственный класс Application в свое приложение, добавив атрибут android:name к элементу <application> в манифесте Android. Не забудьте сделать это!
  • Используйте Timber.i() для записи сообщений журнала с помощью Timber . Этот метод принимает только один аргумент: сообщение для записи. Тег журнала (имя класса) добавляется для вас автоматически.

Удасити курс:

Документация для разработчиков Android:

Другой:

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

  • При необходимости задайте домашнее задание.
  • Объясните учащимся, как сдавать домашние задания.
  • Оценивайте домашние задания.

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

Если вы работаете с этой кодовой лабораторией самостоятельно, не стесняйтесь использовать эти домашние задания, чтобы проверить свои знания.

Изменить приложение

Откройте приложение DiceRoller из Урока 1. (Вы можете загрузить приложение DiceRoller здесь , если у вас его нет.) Добавьте в это приложение поддержку Timber, используя тот же процесс, что и для приложения DessertClicker. Переопределите все обратные вызовы жизненного цикла и добавьте сообщения журнала для каждого обратного вызова.

Ответьте на эти вопросы

Вопрос 1

Что из следующего НЕ является состоянием жизненного цикла деятельности?

  • Начал
  • Ожидающий
  • Созданный
  • Разрушен

вопрос 2

Какой метод жизненного цикла вызывается, чтобы сделать активность видимой?

  • onPause()
  • onVisible()
  • onStart()
  • onDestroy()

Вопрос 3

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

  • onResume()
  • onVisible()
  • onStart()
  • onFocus()

Вопрос 4

Когда onCreate() вызывается в действии?

  • Каждый раз активность видна пользователю.
  • Каждый раз активность возвращается из фона.
  • Только один раз, когда активность создается.
  • Только один раз, когда деятельность возобновится.

Отправьте свое приложение на оценку

Убедитесь, что приложение имеет следующее:

  • Зависимость от Timber в файле build.gradle для приложения.
  • Пользовательский подкласс Application , который инициализирует Timber в onCreate() .
  • Атрибут для этого пользовательского подкласса в манифесте Android.
  • Переопределение методов в MainActivity для всех методов обратного вызова жизненного цикла с вызовами Timber.i() для ведения журнала.

Начать следующий урок: 4.2: Сложные ситуации жизненного цикла

Ссылки на другие лаборатории кода в этом курсе см. на целевой странице лаборатории кода Android Kotlin Fundamentals .