1. Добро пожаловать
Эта практическая лаборатория кода является частью раздела 1 «Начало работы» курса «Основы разработки Android (версия 2)». Вы получите максимальную пользу от этого курса, если будете последовательно проходить лабораторные работы по коду:
- Полный список лабораторных работ курса см. в разделе «Основы разработки кода для Android (V2)».
- Подробную информацию о курсе, включая ссылки на все концептуальные главы, приложения и слайды, см. в разделе «Основы разработки Android (версия 2)».
Введение
В этом практическом занятии вы узнаете больше о жизненном цикле активности. Жизненный цикл — это набор состояний, в которых активность может находиться в течение всего своего существования, с момента ее создания до момента ее уничтожения и восстановления системой своих ресурсов. Когда пользователь перемещается между действиями в вашем приложении (а также между входами и выходами из вашего приложения), действия переходят из одного состояния в свой жизненный цикл.
Каждому этапу жизненного цикла активности соответствует соответствующий метод обратного вызова: onCreate(), onStart(), onPause() и т. д. Когда действие меняет состояние, вызывается соответствующий метод обратного вызова. Вы уже видели один из этих методов: onCreate(). Переопределяя любой из методов обратного вызова жизненного цикла в ваших классах активности, вы можете изменить поведение активности по умолчанию в ответ на действия пользователя или системы.
Состояние активности также может меняться в ответ на изменения конфигурации устройства, например, когда пользователь поворачивает устройство из книжной ориентации в альбомную. Когда происходят эти изменения конфигурации, действие уничтожается и воссоздается в состоянии по умолчанию, и пользователь может потерять информацию, которую он ввел в действие. Чтобы не вводить пользователей в заблуждение, важно разработать свое приложение таким образом, чтобы предотвратить непредвиденную потерю данных. Далее в этом практическом занятии вы поэкспериментируете с изменениями конфигурации и узнаете, как сохранять состояние действия в ответ на изменения конфигурации устройства и другие события жизненного цикла действия.
В этом практическом занятии вы добавите операторы журналирования в приложение TwoActivities и будете наблюдать за изменениями жизненного цикла действий по мере использования приложения. Затем вы начинаете работать с этими изменениями и изучать, как обрабатывать ввод пользователя в этих условиях.
Предварительные условия
Вы должны быть в состоянии:
- Создайте и запустите проект приложения в Android Studio .
- Добавьте операторы журнала в свое приложение и просматривайте эти журналы на панели Logcat.
- Понимайте и работайте с Действием и Намерением, а также будьте комфортно с ними взаимодействовать.
Что вы узнаете
- Как работает жизненный цикл Activity.
- Когда действие запускается, приостанавливается, останавливается и уничтожается.
- О методах обратного вызова жизненного цикла, связанных с изменениями активности.
- Эффект действий (например, изменений конфигурации), которые могут привести к событиям жизненного цикла действия.
- Как сохранить состояние активности во время событий жизненного цикла.
Что ты будешь делать
- Добавьте в приложение TwoActivities код из предыдущего практического занятия, чтобы реализовать различные обратные вызовы жизненного цикла активности и включить операторы журналирования.
- Наблюдайте за изменениями состояния при запуске вашего приложения и при взаимодействии с каждым действием в вашем приложении.
- Измените свое приложение, чтобы сохранить состояние экземпляра действия, которое неожиданно воссоздается в ответ на поведение пользователя или изменение конфигурации на устройстве.
2. Обзор приложения
В этом практическом занятии вы добавите приложение TwoActivities . Приложение выглядит и ведет себя примерно так же, как и в последней кодовой лаборатории. Он содержит две реализации Activity и дает пользователю возможность отправлять данные между ними. Изменения, которые вы внесете в приложение в этом практическом занятии, не повлияют на его видимое поведение пользователя.
3. 3. Задача 1. Добавьте обратные вызовы жизненного цикла в TwoActivities.
В этой задаче вы реализуете все методы обратного вызова жизненного цикла Activity для вывода сообщений в logcat при вызове этих методов. Эти сообщения журнала позволят вам увидеть, когда изменяется состояние жизненного цикла активности, и как эти изменения состояния жизненного цикла влияют на ваше приложение во время его работы.
1.1 (Необязательно) Скопируйте проект TwoActivities.
Для выполнения задач этого практического занятия вы измените существующий проект TwoActivities , который вы создали на последнем практическом занятии. Если вы предпочитаете сохранить предыдущий проект TwoActivities нетронутым, выполните действия, описанные в Приложении: Утилиты , чтобы сделать копию проекта.
1.2 Реализация обратных вызовов в MainActivity
- Откройте проект TwoActivities в Android Studio и откройте MainActivity на панели «Проект» > Android.
- В методе onCreate() добавьте следующие операторы журнала:
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
- Добавьте переопределение для обратного вызова onStart() с оператором в журнале для этого события:
@Override
public void onStart(){
super.onStart();
Log.d(LOG_TAG, "onStart");
}
Для ярлыка выберите «Код» > «Переопределить методы» в Android Studio. Появится диалоговое окно со всеми возможными методами, которые вы можете переопределить в своем классе. Выбор одного или нескольких методов обратного вызова из списка вставляет полный шаблон для этих методов, включая необходимый вызов суперкласса.
- Используйте метод onStart() в качестве шаблона для реализации обратных вызовов жизненного цикла onPause(), onRestart(), onResume(), onStop() и onDestroy().
Все методы обратного вызова имеют одинаковые сигнатуры (кроме имени). Если вы копируете и вставляете onStart() для создания этих других методов обратного вызова, не забудьте обновить содержимое, чтобы вызвать правильный метод в суперклассе и зарегистрировать правильный метод.
- Запустите свое приложение.
- Нажмите вкладку Logcat в нижней части Android Studio, чтобы отобразить панель Logcat. Вы должны увидеть три сообщения журнала, показывающие три состояния жизненного цикла, через которые прошло действие при запуске:
D/MainActivity: -------
D/MainActivity: onCreate
D/MainActivity: onStart
D/MainActivity: onResume
1.3 Реализация обратных вызовов жизненного цикла в SecondActivity
Теперь, когда вы реализовали методы обратного вызова жизненного цикла для MainActivity, сделайте то же самое для SecondActivity.
- Откройте SecondActivity.
- В верхней части класса добавьте константу для переменной LOG_TAG:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
- Добавьте обратные вызовы жизненного цикла и операторы журнала во второе действие. (Вы можете скопировать и вставить методы обратного вызова из MainActivity.)
- Добавьте оператор журнала в метод returnReply() непосредственно перед методом Finish():
Log.d(LOG_TAG, "End SecondActivity");
1.4. Просмотрите журнал во время работы приложения**
- Запустите свое приложение.
- Нажмите вкладку Logcat в нижней части Android Studio, чтобы отобразить панель Logcat.
- Введите «Активность» в поле поиска. Логарифм Android может быть очень длинным и запутанным. Поскольку переменная LOG_TAG в каждом классе содержит слова MainActivity или SecondActivity, это ключевое слово позволяет фильтровать журнал только по тем вещам, которые вас интересуют.
Поэкспериментируйте с приложением и обратите внимание, что события жизненного цикла происходят в ответ на различные действия. В частности, попробуйте следующее:
- Используйте приложение как обычно (отправьте сообщение, ответьте другим сообщением).
- Используйте кнопку «Назад», чтобы вернуться от второго действия к основному действию.
- Используйте стрелку вверх на панели приложения, чтобы вернуться от второго действия к основному действию.
- Вращайте устройство как в основной, так и во второй активности в разное время в вашем приложении и наблюдайте, что * происходит в журнале и на экране.
- Нажмите кнопку обзора (квадратная кнопка справа от «Домой») и закройте приложение (коснитесь X).
- Вернитесь на главный экран и перезапустите приложение.
СОВЕТ: Если вы запускаете приложение в эмуляторе, вы можете имитировать вращение с помощью Control+F11 или Control+Function+F11.
Код решения задачи 1
В следующих фрагментах кода показан код решения для первой задачи.
Основная деятельность
Следующие фрагменты кода показывают добавленный код в MainActivity, но не весь класс.
Метод onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Log the start of the onCreate() method.
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
}
Другие методы жизненного цикла:
@Override
protected void onStart() {
super.onStart();
Log.d(LOG_TAG, "onStart");
}
@Override
protected void onPause() {
super.onPause();
Log.d(LOG_TAG, "onPause");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(LOG_TAG, "onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(LOG_TAG, "onResume");
}
@Override
protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "onDestroy");
}
Вторая активность
В следующих фрагментах кода показан добавленный код в SecondActivity, но не весь класс.
В верхней части класса SecondActivity:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
Метод returnReply():
public void returnReply(View view) {
String reply = mReply.getText().toString();
Intent replyIntent = new Intent();
replyIntent.putExtra(EXTRA_REPLY, reply);
setResult(RESULT_OK, replyIntent);
Log.d(LOG_TAG, "End SecondActivity");
finish();
}
Другие методы жизненного цикла:
То же, что и для MainActivity выше.
4. 4. Задача 2. Сохраните и восстановите состояние экземпляра Activity.
В зависимости от системных ресурсов и поведения пользователя каждое действие в вашем приложении может уничтожаться и восстанавливаться гораздо чаще, чем вы думаете.
Возможно, вы заметили такое поведение в последнем разделе, когда поворачивали устройство или эмулятор. Поворот устройства является одним из примеров изменения конфигурации устройства. Хотя ротация является наиболее распространенной, все изменения конфигурации приводят к уничтожению текущего действия и его воссозданию, как если бы оно было новым. Если вы не учтете это поведение в своем коде, то при изменении конфигурации макет вашей активности может вернуться к внешнему виду и исходным значениям по умолчанию, а ваши пользователи могут потерять свое место, свои данные или состояние своего прогресса в работе. ваше приложение.
Состояние каждого действия хранится в виде набора пар ключ/значение в объекте Bundle, который называется состоянием экземпляра действия. Система сохраняет информацию о состоянии по умолчанию в пакете состояния экземпляра непосредственно перед остановкой действия и передает этот пакет новому экземпляру действия для восстановления.
Чтобы не потерять данные в действии при его неожиданном уничтожении и воссоздании, вам необходимо реализовать метод onSaveInstanceState(). Система вызывает этот метод для вашего действия (между onPause() и onStop()), когда существует вероятность того, что действие может быть уничтожено и воссоздано.
Данные, которые вы сохраняете в состоянии экземпляра, относятся только к этому экземпляру этого конкретного действия во время текущего сеанса приложения. Когда вы останавливаете и перезапускаете новый сеанс приложения, состояние экземпляра действия теряется, и действие возвращается к виду по умолчанию. Если вам нужно сохранять пользовательские данные между сеансами приложения, используйте общие настройки или базу данных. Вы узнаете об обоих из них на следующем практическом занятии.
2.1. Сохраните состояние экземпляра Activity с помощью onSaveInstanceState().
Возможно, вы заметили, что поворот устройства вообще не влияет на состояние второго Activity. Это связано с тем, что второй макет и состояние действия генерируются на основе макета и намерения, которое его активировало. Даже если действие создается заново, намерение все еще существует, и данные в этом намерении по-прежнему используются каждый раз, когда вызывается метод onCreate() во втором действии.
Кроме того, вы можете заметить, что в каждом действии любой текст, введенный вами в элементы EditText сообщения или ответа, сохраняется даже при повороте устройства. Это связано с тем, что информация о состоянии некоторых элементов представления в вашем макете автоматически сохраняется при изменении конфигурации, и текущее значение EditText является одним из таких случаев.
Таким образом, единственное состояние действия, которое вас интересует, — это элементы TextView для заголовка ответа и текст ответа в основном действии. Оба элемента TextView по умолчанию невидимы; они появляются только после того, как вы отправите сообщение обратно в основное действие из второго действия.
В этой задаче вы добавляете код для сохранения состояния экземпляра этих двух элементов TextView с помощью onSaveInstanceState().
- Откройте MainActivity.
- Добавьте эту скелетную реализацию onSaveInstanceState() в действие или используйте «Код» > «Методы переопределения», чтобы вставить переопределение скелета.
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
- Проверьте, виден ли в данный момент заголовок, и если да, поместите это состояние видимости в состояние Bundle с помощью метода putBoolean() и ключа «reply_visible».
if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
outState.putBoolean("reply_visible", true);
}
Помните, что заголовок и текст ответа помечаются как невидимые до тех пор, пока не будет получен ответ от второго действия. Если заголовок виден, значит, есть данные ответа, которые необходимо сохранить. Обратите внимание, что нас интересует только это состояние видимости — фактический текст заголовка не нужно сохранять, поскольку этот текст никогда не меняется.
- Внутри этой же проверки добавьте текст ответа в Bundle.
outState.putString("reply_text",mReplyTextView.getText().toString());
Если заголовок виден, вы можете предположить, что само ответное сообщение также видно. Вам не нужно проверять или сохранять текущее состояние видимости ответного сообщения. В состояние Bundle переходит только сам текст сообщения с ключом «reply_text».
Вы сохраняете состояние только тех элементов представления, которые могут измениться после создания действия. Другие элементы View в вашем приложении (EditText, Button) можно в любое время воссоздать из макета по умолчанию.
Обратите внимание, что система сохранит состояние некоторых элементов представления, например содержимого EditText.
2.2. Восстановите состояние экземпляра Activity в onCreate().
После того как вы сохранили состояние экземпляра действия, вам также необходимо восстановить его при повторном создании действия. Вы можете сделать это либо в onCreate(), либо реализовав обратный вызов onRestoreInstanceState(), который вызывается после onStart() после создания действия.
В большинстве случаев лучшим местом для восстановления состояния активности является onCreate(), чтобы гарантировать, что пользовательский интерфейс, включая состояние, будет доступен как можно скорее. Иногда удобно сделать это в onRestoreInstanceState() после завершения всей инициализации или позволить подклассам решить, использовать ли вашу реализацию по умолчанию.
- В методе onCreate() после инициализации переменных View с помощью findViewById() добавьте тест, чтобы убедиться, что saveInstanceState не имеет значения null.
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
// Restore the state.
if (savedInstanceState != null) {
}
Когда ваша активность создается, система передает состояние Bundle в onCreate() в качестве единственного аргумента. При первом вызове onCreate() и запуске вашего приложения Bundle имеет значение null — при первом запуске вашего приложения никакого существующего состояния не существует. При последующих вызовах onCreate() пакет заполняется данными, которые вы сохранили в onSaveInstanceState().
- Внутри этой проверки получите текущую видимость (истину или ложь) из пакета с помощью ключа «reply_visible».
if (savedInstanceState != null) {
boolean isVisible =
savedInstanceState.getBoolean("reply_visible");
}
- Добавьте тест ниже предыдущей строки для переменной isVisible.
if (isVisible) {
}
Если в состоянии Bundle есть ключ response_visible (и, следовательно, isVisible имеет значение true), вам потребуется восстановить состояние.
- Внутри теста isVisible сделайте заголовок видимым.
mReplyHeadTextView.setVisibility(View.VISIBLE);
- Получите текстовое ответное сообщение из пакета с ключом «reply_text» и настройте TextView ответа на отображение этой строки.
mReplyTextView.setText(savedInstanceState.getString("reply_text"));
- Сделайте также ответ TextView видимым:
mReplyTextView.setVisibility(View.VISIBLE);
- Запустите приложение. Попробуйте повернуть устройство или эмулятор, чтобы ответное сообщение (если оно есть) оставалось на экране после воссоздания действия.
Код решения задачи 2
В следующих фрагментах кода показан код решения для этой задачи.
Основная деятельность
Следующие фрагменты кода показывают добавленный код в MainActivity, но не весь класс.
Метод onSaveInstanceState():
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// If the heading is visible, message needs to be saved.
// Otherwise we're still using default layout.
if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
outState.putBoolean("reply_visible", true);
outState.putString("reply_text",
mReplyTextView.getText().toString());
}
}
Метод onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
// Restore the saved state.
// See onSaveInstanceState() for what gets saved.
if (savedInstanceState != null) {
boolean isVisible =
savedInstanceState.getBoolean("reply_visible");
// Show both the header and the message views. If isVisible is
// false or missing from the bundle, use the default layout.
if (isVisible) {
mReplyHeadTextView.setVisibility(View.VISIBLE);
mReplyTextView.setText(savedInstanceState
.getString("reply_text"));
mReplyTextView.setVisibility(View.VISIBLE);
}
}
}
Полный проект:
Проект Android Studio: TwoActivitiesLifecycle
5. Кодирование
Задача: создать простое приложение со списком покупок с основным действием для списка, который создает пользователь, и вторым действием для списка распространенных товаров для покупок.
- Основное действие должно содержать список для построения, который должен состоять из десяти пустых элементов TextView.
- Кнопка «Добавить товар» в основном действии запускает второе действие, содержащее список распространенных товаров для покупок (сыр, рис, яблоки и т. д.). Используйте элементы Button для отображения элементов.
- Выбор элемента возвращает пользователя к основному действию и обновляет пустой TextView, включив в него выбранный элемент.
Используйте намерение для передачи информации из одного действия в другое. Убедитесь, что текущее состояние списка покупок сохраняется, когда пользователь поворачивает устройство.
6. Резюме
- Жизненный цикл действия — это набор состояний, через которые проходит действие, начиная с момента его первого создания и заканчивая моментом, когда система Android восстанавливает ресурсы для этого действия.
- Когда пользователь переходит от одного действия к другому, внутри и снаружи вашего приложения, каждое действие перемещается между состояниями жизненного цикла действия.
- Каждое состояние жизненного цикла Activity имеет соответствующий метод обратного вызова, который вы можете переопределить в своем классе Activity.
- Методами жизненного цикла являются onCreate(), onStart(), onPause(), onRestart(), onResume(), onStop(), onDestroy().
- Переопределение метода обратного вызова жизненного цикла позволяет вам добавить поведение, которое происходит, когда ваше действие переходит в это состояние.
- Вы можете добавить методы переопределения скелета в свои классы в Android Studio, выбрав «Код» > «Переопределить».
- Изменения конфигурации устройства, такие как ротация, приводят к уничтожению и воссозданию действия, как если бы оно было новым.
- Часть состояния Activity сохраняется при изменении конфигурации, включая текущие значения элементов EditText. Для всех остальных данных вы должны явно сохранить эти данные самостоятельно.
- Сохраните состояние экземпляра Activity в методе onSaveInstanceState().
- Данные о состоянии экземпляра хранятся в виде простых пар ключ/значение в пакете. Используйте методы Bundle для помещения данных в Bundle и получения данных обратно из него.
- Восстановите состояние экземпляра с помощью onCreate() (предпочтительный способ) или onRestoreInstanceState(). Назад
1. Добро пожаловать
Эта практическая лаборатория кода является частью раздела 1 «Начало работы» курса «Основы разработки Android (версия 2)». Вы получите максимальную пользу от этого курса, если будете последовательно проходить лабораторные работы по коду:
- Полный список лабораторных работ курса см. в разделе «Основы разработки кода для Android (V2)».
- Подробную информацию о курсе, включая ссылки на все концептуальные главы, приложения и слайды, см. в разделе «Основы разработки Android (версия 2)».
Введение
В этом практическом занятии вы узнаете больше о жизненном цикле активности. Жизненный цикл — это набор состояний, в которых активность может находиться в течение всего своего существования, с момента ее создания до момента ее уничтожения и восстановления системой своих ресурсов. Когда пользователь перемещается между действиями в вашем приложении (а также между входами и выходами из вашего приложения), действия переходят из одного состояния в свой жизненный цикл.
Каждому этапу жизненного цикла активности соответствует соответствующий метод обратного вызова: onCreate(), onStart(), onPause() и т. д. Когда действие меняет состояние, вызывается соответствующий метод обратного вызова. Вы уже видели один из этих методов: onCreate(). Переопределяя любой из методов обратного вызова жизненного цикла в ваших классах активности, вы можете изменить поведение активности по умолчанию в ответ на действия пользователя или системы.
Состояние активности также может меняться в ответ на изменения конфигурации устройства, например, когда пользователь поворачивает устройство из книжной ориентации в альбомную. Когда происходят эти изменения конфигурации, действие уничтожается и воссоздается в состоянии по умолчанию, и пользователь может потерять информацию, которую он ввел в действие. Чтобы не вводить пользователей в заблуждение, важно разработать свое приложение таким образом, чтобы предотвратить непредвиденную потерю данных. Далее в этом практическом занятии вы поэкспериментируете с изменениями конфигурации и узнаете, как сохранять состояние действия в ответ на изменения конфигурации устройства и другие события жизненного цикла действия.
В этом практическом занятии вы добавите операторы журналирования в приложение TwoActivities и будете наблюдать за изменениями жизненного цикла действий по мере использования приложения. Затем вы начинаете работать с этими изменениями и изучать, как обрабатывать ввод пользователя в этих условиях.
Предварительные условия
Вы должны быть в состоянии:
- Создайте и запустите проект приложения в Android Studio .
- Добавьте операторы журнала в свое приложение и просматривайте эти журналы на панели Logcat.
- Понимайте и работайте с Действием и Намерением, а также будьте комфортно с ними взаимодействовать.
Что вы узнаете
- Как работает жизненный цикл Activity.
- Когда действие запускается, приостанавливается, останавливается и уничтожается.
- О методах обратного вызова жизненного цикла, связанных с изменениями активности.
- Эффект действий (например, изменений конфигурации), которые могут привести к событиям жизненного цикла действия.
- Как сохранить состояние активности во время событий жизненного цикла.
Что ты будешь делать
- Добавьте в приложение TwoActivities код из предыдущего практического занятия, чтобы реализовать различные обратные вызовы жизненного цикла активности и включить операторы журналирования.
- Наблюдайте за изменениями состояния при запуске вашего приложения и при взаимодействии с каждым действием в вашем приложении.
- Измените свое приложение, чтобы сохранить состояние экземпляра действия, которое неожиданно воссоздается в ответ на поведение пользователя или изменение конфигурации на устройстве.
2. Обзор приложения
В этом практическом занятии вы добавите приложение TwoActivities . Приложение выглядит и ведет себя примерно так же, как и в последней кодовой лаборатории. Он содержит две реализации Activity и дает пользователю возможность отправлять данные между ними. Изменения, которые вы внесете в приложение в этом практическом занятии, не повлияют на его видимое поведение пользователя.
3. 3. Задача 1. Добавьте обратные вызовы жизненного цикла в TwoActivities.
В этой задаче вы реализуете все методы обратного вызова жизненного цикла Activity для вывода сообщений в logcat при вызове этих методов. Эти сообщения журнала позволят вам увидеть, когда изменяется состояние жизненного цикла активности, и как эти изменения состояния жизненного цикла влияют на ваше приложение во время его работы.
1.1 (Необязательно) Скопируйте проект TwoActivities.
Для выполнения задач этого практического занятия вы измените существующий проект TwoActivities , который вы создали на последнем практическом занятии. Если вы предпочитаете сохранить предыдущий проект TwoActivities нетронутым, выполните действия, описанные в Приложении: Утилиты , чтобы сделать копию проекта.
1.2 Реализация обратных вызовов в MainActivity
- Откройте проект TwoActivities в Android Studio и откройте MainActivity на панели «Проект» > Android.
- В методе onCreate() добавьте следующие операторы журнала:
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
- Добавьте переопределение для обратного вызова onStart() с оператором в журнале для этого события:
@Override
public void onStart(){
super.onStart();
Log.d(LOG_TAG, "onStart");
}
Для ярлыка выберите «Код» > «Переопределить методы» в Android Studio. Появится диалоговое окно со всеми возможными методами, которые вы можете переопределить в своем классе. Выбор одного или нескольких методов обратного вызова из списка вставляет полный шаблон для этих методов, включая необходимый вызов суперкласса.
- Используйте метод onStart() в качестве шаблона для реализации обратных вызовов жизненного цикла onPause(), onRestart(), onResume(), onStop() и onDestroy().
Все методы обратного вызова имеют одинаковые сигнатуры (кроме имени). Если вы копируете и вставляете onStart() для создания этих других методов обратного вызова, не забудьте обновить содержимое, чтобы вызвать правильный метод в суперклассе и зарегистрировать правильный метод.
- Запустите свое приложение.
- Нажмите вкладку Logcat в нижней части Android Studio, чтобы отобразить панель Logcat. Вы должны увидеть три сообщения журнала, показывающие три состояния жизненного цикла, через которые прошло действие при запуске:
D/MainActivity: -------
D/MainActivity: onCreate
D/MainActivity: onStart
D/MainActivity: onResume
1.3 Реализация обратных вызовов жизненного цикла в SecondActivity
Теперь, когда вы реализовали методы обратного вызова жизненного цикла для MainActivity, сделайте то же самое для SecondActivity.
- Откройте SecondActivity.
- В верхней части класса добавьте константу для переменной LOG_TAG:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
- Добавьте обратные вызовы жизненного цикла и операторы журнала во второе действие. (Вы можете скопировать и вставить методы обратного вызова из MainActivity.)
- Добавьте оператор журнала в метод returnReply() непосредственно перед методом Finish():
Log.d(LOG_TAG, "End SecondActivity");
1.4. Просмотрите журнал во время работы приложения**
- Запустите свое приложение.
- Нажмите вкладку Logcat в нижней части Android Studio, чтобы отобразить панель Logcat.
- Введите «Активность» в поле поиска. Логарифм Android может быть очень длинным и запутанным. Поскольку переменная LOG_TAG в каждом классе содержит слова MainActivity или SecondActivity, это ключевое слово позволяет фильтровать журнал только по тем вещам, которые вас интересуют.
Поэкспериментируйте с приложением и обратите внимание, что события жизненного цикла происходят в ответ на различные действия. В частности, попробуйте следующее:
- Используйте приложение как обычно (отправьте сообщение, ответьте другим сообщением).
- Используйте кнопку «Назад», чтобы вернуться от второго действия к основному действию.
- Используйте стрелку вверх на панели приложения, чтобы вернуться от второго действия к основному действию.
- Вращайте устройство как в основной, так и во второй активности в разное время в вашем приложении и наблюдайте, что * происходит в журнале и на экране.
- Нажмите кнопку обзора (квадратная кнопка справа от «Домой») и закройте приложение (коснитесь X).
- Вернитесь на главный экран и перезапустите приложение.
СОВЕТ: Если вы запускаете приложение в эмуляторе, вы можете имитировать вращение с помощью Control+F11 или Control+Function+F11.
Код решения задачи 1
В следующих фрагментах кода показан код решения для первой задачи.
Основная деятельность
Следующие фрагменты кода показывают добавленный код в MainActivity, но не весь класс.
Метод onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Log the start of the onCreate() method.
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
}
Другие методы жизненного цикла:
@Override
protected void onStart() {
super.onStart();
Log.d(LOG_TAG, "onStart");
}
@Override
protected void onPause() {
super.onPause();
Log.d(LOG_TAG, "onPause");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(LOG_TAG, "onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(LOG_TAG, "onResume");
}
@Override
protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "onDestroy");
}
Вторая активность
В следующих фрагментах кода показан добавленный код в SecondActivity, но не весь класс.
В верхней части класса SecondActivity:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
Метод returnReply():
public void returnReply(View view) {
String reply = mReply.getText().toString();
Intent replyIntent = new Intent();
replyIntent.putExtra(EXTRA_REPLY, reply);
setResult(RESULT_OK, replyIntent);
Log.d(LOG_TAG, "End SecondActivity");
finish();
}
Другие методы жизненного цикла:
То же, что и для MainActivity выше.
4. 4. Задача 2. Сохраните и восстановите состояние экземпляра Activity.
В зависимости от системных ресурсов и поведения пользователя каждое действие в вашем приложении может уничтожаться и восстанавливаться гораздо чаще, чем вы думаете.
Возможно, вы заметили такое поведение в последнем разделе, когда поворачивали устройство или эмулятор. Поворот устройства является одним из примеров изменения конфигурации устройства. Хотя ротация является наиболее распространенной, все изменения конфигурации приводят к уничтожению текущего действия и его воссозданию, как если бы оно было новым. Если вы не учтете это поведение в своем коде, то при изменении конфигурации макет вашей активности может вернуться к внешнему виду и исходным значениям по умолчанию, а ваши пользователи могут потерять свое место, свои данные или состояние своего прогресса в работе. ваше приложение.
Состояние каждого действия хранится в виде набора пар ключ/значение в объекте Bundle, который называется состоянием экземпляра действия. Система сохраняет информацию о состоянии по умолчанию в пакете состояния экземпляра непосредственно перед остановкой действия и передает этот пакет новому экземпляру действия для восстановления.
Чтобы не потерять данные в действии при его неожиданном уничтожении и воссоздании, вам необходимо реализовать метод onSaveInstanceState(). Система вызывает этот метод для вашего действия (между onPause() и onStop()), когда существует вероятность того, что действие может быть уничтожено и воссоздано.
Данные, которые вы сохраняете в состоянии экземпляра, относятся только к этому экземпляру этого конкретного действия во время текущего сеанса приложения. Когда вы останавливаете и перезапускаете новый сеанс приложения, состояние экземпляра действия теряется, и действие возвращается к виду по умолчанию. Если вам нужно сохранять пользовательские данные между сеансами приложения, используйте общие настройки или базу данных. Вы узнаете об обоих из них на следующем практическом занятии.
2.1. Сохраните состояние экземпляра Activity с помощью onSaveInstanceState().
Возможно, вы заметили, что поворот устройства вообще не влияет на состояние второго Activity. Это связано с тем, что второй макет и состояние действия генерируются на основе макета и намерения, которое его активировало. Даже если действие создается заново, намерение все еще существует, и данные в этом намерении по-прежнему используются каждый раз, когда вызывается метод onCreate() во втором действии.
Кроме того, вы можете заметить, что в каждом действии любой текст, введенный вами в элементы EditText сообщения или ответа, сохраняется даже при повороте устройства. Это связано с тем, что информация о состоянии некоторых элементов представления в вашем макете автоматически сохраняется при изменении конфигурации, и текущее значение EditText является одним из таких случаев.
Таким образом, единственное состояние действия, которое вас интересует, — это элементы TextView для заголовка ответа и текст ответа в основном действии. Оба элемента TextView по умолчанию невидимы; они появляются только после того, как вы отправите сообщение обратно в основное действие из второго действия.
В этой задаче вы добавляете код для сохранения состояния экземпляра этих двух элементов TextView с помощью onSaveInstanceState().
- Откройте MainActivity.
- Добавьте эту скелетную реализацию onSaveInstanceState() в действие или используйте «Код» > «Методы переопределения», чтобы вставить переопределение скелета.
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
- Проверьте, виден ли в данный момент заголовок, и если да, поместите это состояние видимости в состояние Bundle с помощью метода putBoolean() и ключа «reply_visible».
if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
outState.putBoolean("reply_visible", true);
}
Помните, что заголовок и текст ответа помечаются как невидимые до тех пор, пока не будет получен ответ от второго действия. Если заголовок виден, значит, есть данные ответа, которые необходимо сохранить. Обратите внимание, что нас интересует только это состояние видимости — фактический текст заголовка не нужно сохранять, поскольку этот текст никогда не меняется.
- Внутри этой же проверки добавьте текст ответа в Bundle.
outState.putString("reply_text",mReplyTextView.getText().toString());
Если заголовок виден, вы можете предположить, что само ответное сообщение также видно. Вам не нужно проверять или сохранять текущее состояние видимости ответного сообщения. В состояние Bundle переходит только сам текст сообщения с ключом «reply_text».
Вы сохраняете состояние только тех элементов представления, которые могут измениться после создания действия. Другие элементы View в вашем приложении (EditText, Button) можно в любое время воссоздать из макета по умолчанию.
Обратите внимание, что система сохранит состояние некоторых элементов представления, например содержимого EditText.
2.2. Восстановите состояние экземпляра Activity в onCreate().
После того как вы сохранили состояние экземпляра действия, вам также необходимо восстановить его при повторном создании действия. Вы можете сделать это либо в onCreate(), либо реализовав обратный вызов onRestoreInstanceState(), который вызывается после onStart() после создания действия.
В большинстве случаев лучшим местом для восстановления состояния активности является onCreate(), чтобы гарантировать, что пользовательский интерфейс, включая состояние, будет доступен как можно скорее. Иногда удобно сделать это в onRestoreInstanceState() после завершения всей инициализации или позволить подклассам решить, использовать ли вашу реализацию по умолчанию.
- В методе onCreate() после инициализации переменных View с помощью findViewById() добавьте тест, чтобы убедиться, что saveInstanceState не имеет значения null.
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
// Restore the state.
if (savedInstanceState != null) {
}
Когда ваша активность создается, система передает состояние Bundle в onCreate() в качестве единственного аргумента. При первом вызове onCreate() и запуске вашего приложения Bundle имеет значение null — при первом запуске вашего приложения никакого существующего состояния не существует. При последующих вызовах onCreate() пакет заполняется данными, которые вы сохранили в onSaveInstanceState().
- Внутри этой проверки получите текущую видимость (истину или ложь) из пакета с помощью ключа «reply_visible».
if (savedInstanceState != null) {
boolean isVisible =
savedInstanceState.getBoolean("reply_visible");
}
- Добавьте тест ниже предыдущей строки для переменной isVisible.
if (isVisible) {
}
Если в состоянии Bundle есть ключ response_visible (и, следовательно, isVisible имеет значение true), вам потребуется восстановить состояние.
- Внутри теста isVisible сделайте заголовок видимым.
mReplyHeadTextView.setVisibility(View.VISIBLE);
- Получите текстовое ответное сообщение из пакета с ключом «reply_text» и настройте TextView ответа на отображение этой строки.
mReplyTextView.setText(savedInstanceState.getString("reply_text"));
- Сделайте также ответ TextView видимым:
mReplyTextView.setVisibility(View.VISIBLE);
- Запустите приложение. Попробуйте повернуть устройство или эмулятор, чтобы ответное сообщение (если оно есть) оставалось на экране после воссоздания действия.
Код решения задачи 2
В следующих фрагментах кода показан код решения для этой задачи.
Основная деятельность
Следующие фрагменты кода показывают добавленный код в MainActivity, но не весь класс.
Метод onSaveInstanceState():
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// If the heading is visible, message needs to be saved.
// Otherwise we're still using default layout.
if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
outState.putBoolean("reply_visible", true);
outState.putString("reply_text",
mReplyTextView.getText().toString());
}
}
Метод onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
// Restore the saved state.
// See onSaveInstanceState() for what gets saved.
if (savedInstanceState != null) {
boolean isVisible =
savedInstanceState.getBoolean("reply_visible");
// Show both the header and the message views. If isVisible is
// false or missing from the bundle, use the default layout.
if (isVisible) {
mReplyHeadTextView.setVisibility(View.VISIBLE);
mReplyTextView.setText(savedInstanceState
.getString("reply_text"));
mReplyTextView.setVisibility(View.VISIBLE);
}
}
}
Полный проект:
Проект Android Studio: TwoActivitiesLifecycle
5. Кодирование
Задача: создать простое приложение со списком покупок с основным действием для списка, который создает пользователь, и вторым действием для списка распространенных товаров для покупок.
- Основное действие должно содержать список для построения, который должен состоять из десяти пустых элементов TextView.
- Кнопка «Добавить товар» в основном действии запускает второе действие, содержащее список распространенных товаров для покупок (сыр, рис, яблоки и т. д.). Используйте элементы Button для отображения элементов.
- Выбор элемента возвращает пользователя к основному действию и обновляет пустой TextView, включив в него выбранный элемент.
Используйте намерение для передачи информации из одного действия в другое. Убедитесь, что текущее состояние списка покупок сохраняется, когда пользователь поворачивает устройство.
6. Резюме
- Жизненный цикл действия — это набор состояний, через которые проходит действие, начиная с момента его первого создания и заканчивая моментом, когда система Android восстанавливает ресурсы для этого действия.
- Когда пользователь переходит от одного действия к другому, внутри и снаружи вашего приложения, каждое действие перемещается между состояниями жизненного цикла действия.
- Каждое состояние жизненного цикла Activity имеет соответствующий метод обратного вызова, который вы можете переопределить в своем классе Activity.
- Методами жизненного цикла являются onCreate(), onStart(), onPause(), onRestart(), onResume(), onStop(), onDestroy().
- Переопределение метода обратного вызова жизненного цикла позволяет вам добавить поведение, которое происходит, когда ваше действие переходит в это состояние.
- Вы можете добавить методы переопределения скелета в свои классы в Android Studio, выбрав «Код» > «Переопределить».
- Изменения конфигурации устройства, такие как ротация, приводят к уничтожению и воссозданию действия, как если бы оно было новым.
- Часть состояния Activity сохраняется при изменении конфигурации, включая текущие значения элементов EditText. Для всех остальных данных вы должны явно сохранить эти данные самостоятельно.
- Сохраните состояние экземпляра Activity в методе onSaveInstanceState().
- Данные о состоянии экземпляра хранятся в виде простых пар ключ/значение в пакете. Используйте методы Bundle для помещения данных в Bundle и получения данных обратно из него.
- Восстановите состояние экземпляра с помощью onCreate() (предпочтительный способ) или onRestoreInstanceState(). Назад
1. Добро пожаловать
Эта практическая лаборатория кода является частью раздела 1 «Начало работы» курса «Основы разработки Android (версия 2)». Вы получите максимальную пользу от этого курса, если будете последовательно проходить лабораторные работы по коду:
- Полный список лабораторных работ курса см. в разделе «Основы разработки кода для Android (V2)».
- Подробную информацию о курсе, включая ссылки на все концептуальные главы, приложения и слайды, см. в разделе «Основы разработки Android (версия 2)».
Введение
В этом практическом занятии вы узнаете больше о жизненном цикле активности. Жизненный цикл — это набор состояний, в которых активность может находиться в течение всего своего существования, с момента ее создания до момента ее уничтожения и восстановления системой своих ресурсов. Когда пользователь перемещается между действиями в вашем приложении (а также между входами и выходами из вашего приложения), действия переходят из одного состояния в свой жизненный цикл.
Каждому этапу жизненного цикла активности соответствует соответствующий метод обратного вызова: onCreate(), onStart(), onPause() и т. д. Когда действие меняет состояние, вызывается соответствующий метод обратного вызова. Вы уже видели один из этих методов: onCreate(). Переопределяя любой из методов обратного вызова жизненного цикла в ваших классах активности, вы можете изменить поведение активности по умолчанию в ответ на действия пользователя или системы.
Состояние активности также может меняться в ответ на изменения конфигурации устройства, например, когда пользователь поворачивает устройство из книжной ориентации в альбомную. Когда происходят эти изменения конфигурации, действие уничтожается и воссоздается в состоянии по умолчанию, и пользователь может потерять информацию, которую он ввел в действие. Чтобы не вводить пользователей в заблуждение, важно разработать свое приложение таким образом, чтобы предотвратить непредвиденную потерю данных. Далее в этом практическом занятии вы поэкспериментируете с изменениями конфигурации и узнаете, как сохранять состояние действия в ответ на изменения конфигурации устройства и другие события жизненного цикла действия.
В этом практическом занятии вы добавите операторы журналирования в приложение TwoActivities и будете наблюдать за изменениями жизненного цикла действий по мере использования приложения. Затем вы начинаете работать с этими изменениями и изучать, как обрабатывать ввод пользователя в этих условиях.
Предварительные условия
Вы должны быть в состоянии:
- Создайте и запустите проект приложения в Android Studio .
- Добавьте операторы журнала в свое приложение и просматривайте эти журналы на панели Logcat.
- Понимайте и работайте с Действием и Намерением, а также будьте комфортно с ними взаимодействовать.
Что вы узнаете
- Как работает жизненный цикл Activity.
- Когда действие запускается, приостанавливается, останавливается и уничтожается.
- О методах обратного вызова жизненного цикла, связанных с изменениями активности.
- Эффект действий (например, изменений конфигурации), которые могут привести к событиям жизненного цикла действия.
- Как сохранить состояние активности во время событий жизненного цикла.
Что ты будешь делать
- Добавьте в приложение TwoActivities код из предыдущего практического занятия, чтобы реализовать различные обратные вызовы жизненного цикла активности и включить операторы журналирования.
- Наблюдайте за изменениями состояния при запуске вашего приложения и при взаимодействии с каждым действием в вашем приложении.
- Измените свое приложение, чтобы сохранить состояние экземпляра действия, которое неожиданно воссоздается в ответ на поведение пользователя или изменение конфигурации на устройстве.
2. Обзор приложения
В этом практическом занятии вы добавите приложение TwoActivities . Приложение выглядит и ведет себя примерно так же, как и в последней кодовой лаборатории. Он содержит две реализации Activity и дает пользователю возможность отправлять данные между ними. Изменения, которые вы внесете в приложение в этом практическом занятии, не повлияют на его видимое поведение пользователя.
3. 3. Задача 1. Добавьте обратные вызовы жизненного цикла в TwoActivities.
В этой задаче вы реализуете все методы обратного вызова жизненного цикла Activity для вывода сообщений в logcat при вызове этих методов. Эти сообщения журнала позволят вам увидеть, когда изменяется состояние жизненного цикла активности, и как эти изменения состояния жизненного цикла влияют на ваше приложение во время его работы.
1.1 (Необязательно) Скопируйте проект TwoActivities.
Для выполнения задач этого практического занятия вы измените существующий проект TwoActivities , который вы создали на последнем практическом занятии. Если вы предпочитаете сохранить предыдущий проект TwoActivities нетронутым, выполните действия, описанные в Приложении: Утилиты , чтобы сделать копию проекта.
1.2 Реализация обратных вызовов в MainActivity
- Откройте проект TwoActivities в Android Studio и откройте MainActivity на панели «Проект» > Android.
- В методе onCreate() добавьте следующие операторы журнала:
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
- Добавьте переопределение для обратного вызова onStart() с оператором в журнале для этого события:
@Override
public void onStart(){
super.onStart();
Log.d(LOG_TAG, "onStart");
}
Для ярлыка выберите «Код» > «Переопределить методы» в Android Studio. Появится диалоговое окно со всеми возможными методами, которые вы можете переопределить в своем классе. Выбор одного или нескольких методов обратного вызова из списка вставляет полный шаблон для этих методов, включая необходимый вызов суперкласса.
- Используйте метод onStart() в качестве шаблона для реализации обратных вызовов жизненного цикла onPause(), onRestart(), onResume(), onStop() и onDestroy().
Все методы обратного вызова имеют одинаковые сигнатуры (кроме имени). Если вы копируете и вставляете onStart() для создания этих других методов обратного вызова, не забудьте обновить содержимое, чтобы вызвать правильный метод в суперклассе и зарегистрировать правильный метод.
- Запустите свое приложение.
- Нажмите вкладку Logcat в нижней части Android Studio, чтобы отобразить панель Logcat. Вы должны увидеть три сообщения журнала, показывающие три состояния жизненного цикла, через которые прошло действие при запуске:
D/MainActivity: -------
D/MainActivity: onCreate
D/MainActivity: onStart
D/MainActivity: onResume
1.3 Реализация обратных вызовов жизненного цикла в SecondActivity
Теперь, когда вы реализовали методы обратного вызова жизненного цикла для MainActivity, сделайте то же самое для SecondActivity.
- Откройте SecondActivity.
- В верхней части класса добавьте константу для переменной LOG_TAG:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
- Добавьте обратные вызовы жизненного цикла и операторы журнала во второе действие. (Вы можете скопировать и вставить методы обратного вызова из MainActivity.)
- Добавьте оператор журнала в метод returnReply() непосредственно перед методом Finish():
Log.d(LOG_TAG, "End SecondActivity");
1.4. Просмотрите журнал во время работы приложения**
- Запустите свое приложение.
- Нажмите вкладку Logcat в нижней части Android Studio, чтобы отобразить панель Logcat.
- Введите «Активность» в поле поиска. Логарифм Android может быть очень длинным и запутанным. Поскольку переменная LOG_TAG в каждом классе содержит слова MainActivity или SecondActivity, это ключевое слово позволяет фильтровать журнал только по тем вещам, которые вас интересуют.
Поэкспериментируйте с приложением и обратите внимание, что события жизненного цикла происходят в ответ на различные действия. В частности, попробуйте следующее:
- Используйте приложение как обычно (отправьте сообщение, ответьте другим сообщением).
- Используйте кнопку «Назад», чтобы вернуться от второго действия к основному действию.
- Используйте стрелку вверх на панели приложения, чтобы вернуться от второго действия к основному действию.
- Вращайте устройство как в основной, так и во второй активности в разное время в вашем приложении и наблюдайте, что * происходит в журнале и на экране.
- Нажмите кнопку обзора (квадратная кнопка справа от «Домой») и закройте приложение (коснитесь X).
- Вернитесь на главный экран и перезапустите приложение.
СОВЕТ: Если вы запускаете приложение в эмуляторе, вы можете имитировать вращение с помощью Control+F11 или Control+Function+F11.
Код решения задачи 1
В следующих фрагментах кода показан код решения для первой задачи.
Основная деятельность
Следующие фрагменты кода показывают добавленный код в MainActivity, но не весь класс.
Метод onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Log the start of the onCreate() method.
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
}
Другие методы жизненного цикла:
@Override
protected void onStart() {
super.onStart();
Log.d(LOG_TAG, "onStart");
}
@Override
protected void onPause() {
super.onPause();
Log.d(LOG_TAG, "onPause");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(LOG_TAG, "onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(LOG_TAG, "onResume");
}
@Override
protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "onDestroy");
}
Вторая активность
В следующих фрагментах кода показан добавленный код в SecondActivity, но не весь класс.
В верхней части класса SecondActivity:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
Метод returnReply():
public void returnReply(View view) {
String reply = mReply.getText().toString();
Intent replyIntent = new Intent();
replyIntent.putExtra(EXTRA_REPLY, reply);
setResult(RESULT_OK, replyIntent);
Log.d(LOG_TAG, "End SecondActivity");
finish();
}
Другие методы жизненного цикла:
То же, что и для MainActivity выше.
4. 4. Задача 2. Сохраните и восстановите состояние экземпляра Activity.
В зависимости от системных ресурсов и поведения пользователя каждое действие в вашем приложении может уничтожаться и восстанавливаться гораздо чаще, чем вы думаете.
Возможно, вы заметили такое поведение в последнем разделе, когда поворачивали устройство или эмулятор. Поворот устройства является одним из примеров изменения конфигурации устройства. Хотя ротация является наиболее распространенной, все изменения конфигурации приводят к уничтожению текущего действия и его воссозданию, как если бы оно было новым. Если вы не учтете это поведение в своем коде, то при изменении конфигурации макет вашей активности может вернуться к внешнему виду и исходным значениям по умолчанию, а ваши пользователи могут потерять свое место, свои данные или состояние своего прогресса в работе. ваше приложение.
Состояние каждого действия хранится в виде набора пар ключ/значение в объекте Bundle, который называется состоянием экземпляра действия. Система сохраняет информацию о состоянии по умолчанию в пакете состояния экземпляра непосредственно перед остановкой действия и передает этот пакет новому экземпляру действия для восстановления.
Чтобы не потерять данные в действии при его неожиданном уничтожении и воссоздании, вам необходимо реализовать метод onSaveInstanceState(). Система вызывает этот метод для вашего действия (между onPause() и onStop()), когда существует вероятность того, что действие может быть уничтожено и воссоздано.
Данные, которые вы сохраняете в состоянии экземпляра, относятся только к этому экземпляру этого конкретного действия во время текущего сеанса приложения. Когда вы останавливаете и перезапускаете новый сеанс приложения, состояние экземпляра действия теряется, и действие возвращается к виду по умолчанию. Если вам нужно сохранять пользовательские данные между сеансами приложения, используйте общие настройки или базу данных. Вы узнаете об обоих из них на следующем практическом занятии.
2.1. Сохраните состояние экземпляра Activity с помощью onSaveInstanceState().
Возможно, вы заметили, что поворот устройства вообще не влияет на состояние второго Activity. Это связано с тем, что второй макет и состояние действия генерируются на основе макета и намерения, которое его активировало. Даже если действие создается заново, намерение все еще существует, и данные в этом намерении по-прежнему используются каждый раз, когда вызывается метод onCreate() во втором действии.
Кроме того, вы можете заметить, что в каждом действии любой текст, введенный вами в элементы EditText сообщения или ответа, сохраняется даже при повороте устройства. Это связано с тем, что информация о состоянии некоторых элементов представления в вашем макете автоматически сохраняется при изменении конфигурации, и текущее значение EditText является одним из таких случаев.
Таким образом, единственное состояние действия, которое вас интересует, — это элементы TextView для заголовка ответа и текст ответа в основном действии. Оба элемента TextView по умолчанию невидимы; они появляются только после того, как вы отправите сообщение обратно в основное действие из второго действия.
В этой задаче вы добавляете код для сохранения состояния экземпляра этих двух элементов TextView с помощью onSaveInstanceState().
- Откройте MainActivity.
- Добавьте эту скелетную реализацию onSaveInstanceState() в действие или используйте «Код» > «Методы переопределения», чтобы вставить переопределение скелета.
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
- Проверьте, виден ли в данный момент заголовок, и если да, поместите это состояние видимости в состояние Bundle с помощью метода putBoolean() и ключа «reply_visible».
if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
outState.putBoolean("reply_visible", true);
}
Помните, что заголовок и текст ответа помечаются как невидимые до тех пор, пока не будет получен ответ от второго действия. Если заголовок виден, значит, есть данные ответа, которые необходимо сохранить. Обратите внимание, что нас интересует только это состояние видимости — фактический текст заголовка не нужно сохранять, поскольку этот текст никогда не меняется.
- Внутри этой же проверки добавьте текст ответа в Bundle.
outState.putString("reply_text",mReplyTextView.getText().toString());
Если заголовок виден, вы можете предположить, что само ответное сообщение также видно. Вам не нужно проверять или сохранять текущее состояние видимости ответного сообщения. В состояние Bundle переходит только сам текст сообщения с ключом «reply_text».
Вы сохраняете состояние только тех элементов представления, которые могут измениться после создания действия. Другие элементы View в вашем приложении (EditText, Button) можно в любое время воссоздать из макета по умолчанию.
Обратите внимание, что система сохранит состояние некоторых элементов представления, например содержимого EditText.
2.2. Восстановите состояние экземпляра Activity в onCreate().
После того как вы сохранили состояние экземпляра действия, вам также необходимо восстановить его при повторном создании действия. Вы можете сделать это либо в onCreate(), либо реализовав обратный вызов onRestoreInstanceState(), который вызывается после onStart() после создания действия.
В большинстве случаев лучшим местом для восстановления состояния активности является onCreate(), чтобы гарантировать, что пользовательский интерфейс, включая состояние, будет доступен как можно скорее. Иногда удобно сделать это в onRestoreInstanceState() после завершения всей инициализации или позволить подклассам решить, использовать ли вашу реализацию по умолчанию.
- В методе onCreate() после инициализации переменных View с помощью findViewById() добавьте тест, чтобы убедиться, что saveInstanceState не имеет значения null.
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
// Restore the state.
if (savedInstanceState != null) {
}
Когда ваша активность создается, система передает состояние Bundle в onCreate() в качестве единственного аргумента. При первом вызове onCreate() и запуске вашего приложения Bundle имеет значение null — при первом запуске вашего приложения никакого существующего состояния не существует. При последующих вызовах onCreate() пакет заполняется данными, которые вы сохранили в onSaveInstanceState().
- Внутри этой проверки получите текущую видимость (истину или ложь) из пакета с помощью ключа «reply_visible».
if (savedInstanceState != null) {
boolean isVisible =
savedInstanceState.getBoolean("reply_visible");
}
- Добавьте тест ниже предыдущей строки для переменной isVisible.
if (isVisible) {
}
Если в состоянии Bundle есть ключ response_visible (и, следовательно, isVisible имеет значение true), вам потребуется восстановить состояние.
- Внутри теста isVisible сделайте заголовок видимым.
mReplyHeadTextView.setVisibility(View.VISIBLE);
- Получите текстовое ответное сообщение из пакета с ключом «reply_text» и настройте TextView ответа на отображение этой строки.
mReplyTextView.setText(savedInstanceState.getString("reply_text"));
- Сделайте также ответ TextView видимым:
mReplyTextView.setVisibility(View.VISIBLE);
- Запустите приложение. Попробуйте повернуть устройство или эмулятор, чтобы ответное сообщение (если оно есть) оставалось на экране после воссоздания действия.
Код решения задачи 2
В следующих фрагментах кода показан код решения для этой задачи.
Основная деятельность
Следующие фрагменты кода показывают добавленный код в MainActivity, но не весь класс.
Метод onSaveInstanceState():
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// If the heading is visible, message needs to be saved.
// Otherwise we're still using default layout.
if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
outState.putBoolean("reply_visible", true);
outState.putString("reply_text",
mReplyTextView.getText().toString());
}
}
Метод onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
// Restore the saved state.
// See onSaveInstanceState() for what gets saved.
if (savedInstanceState != null) {
boolean isVisible =
savedInstanceState.getBoolean("reply_visible");
// Show both the header and the message views. If isVisible is
// false or missing from the bundle, use the default layout.
if (isVisible) {
mReplyHeadTextView.setVisibility(View.VISIBLE);
mReplyTextView.setText(savedInstanceState
.getString("reply_text"));
mReplyTextView.setVisibility(View.VISIBLE);
}
}
}
Полный проект:
Проект Android Studio: TwoActivitiesLifecycle
5. Кодирование
Задача: создать простое приложение со списком покупок с основным действием для списка, который создает пользователь, и вторым действием для списка распространенных товаров для покупок.
- Основное действие должно содержать список для построения, который должен состоять из десяти пустых элементов TextView.
- Кнопка «Добавить товар» в основном действии запускает второе действие, содержащее список распространенных товаров для покупок (сыр, рис, яблоки и т. д.). Используйте элементы Button для отображения элементов.
- Выбор элемента возвращает пользователя к основному действию и обновляет пустой TextView, включив в него выбранный элемент.
Используйте намерение для передачи информации из одного действия в другое. Убедитесь, что текущее состояние списка покупок сохраняется, когда пользователь поворачивает устройство.
6. Резюме
- Жизненный цикл действия — это набор состояний, через которые проходит действие, начиная с момента его первого создания и заканчивая моментом, когда система Android восстанавливает ресурсы для этого действия.
- Когда пользователь переходит от одного действия к другому, внутри и снаружи вашего приложения, каждое действие перемещается между состояниями жизненного цикла действия.
- Каждое состояние жизненного цикла Activity имеет соответствующий метод обратного вызова, который вы можете переопределить в своем классе Activity.
- Методами жизненного цикла являются onCreate(), onStart(), onPause(), onRestart(), onResume(), onStop(), onDestroy().
- Переопределение метода обратного вызова жизненного цикла позволяет вам добавить поведение, которое происходит, когда ваше действие переходит в это состояние.
- Вы можете добавить методы переопределения скелета в свои классы в Android Studio, выбрав «Код» > «Переопределить».
- Изменения конфигурации устройства, такие как ротация, приводят к уничтожению и воссозданию действия, как если бы оно было новым.
- Часть состояния Activity сохраняется при изменении конфигурации, включая текущие значения элементов EditText. Для всех остальных данных вы должны явно сохранить эти данные самостоятельно.
- Сохраните состояние экземпляра Activity в методе onSaveInstanceState().
- Данные о состоянии экземпляра хранятся в виде простых пар ключ/значение в пакете. Используйте методы Bundle для помещения данных в Bundle и получения данных обратно из него.
- Восстановите состояние экземпляра с помощью onCreate() (предпочтительный способ) или onRestoreInstanceState(). Назад
1. Добро пожаловать
Эта практическая лаборатория кода является частью раздела 1 «Начало работы» курса «Основы разработки Android (версия 2)». Вы получите максимальную пользу от этого курса, если будете последовательно проходить лабораторные работы по коду:
- Полный список лабораторных работ курса см. в разделе «Основы разработки кода для Android (V2)».
- Подробную информацию о курсе, включая ссылки на все концептуальные главы, приложения и слайды, см. в разделе «Основы разработки Android (версия 2)».
Введение
В этом практическом занятии вы узнаете больше о жизненном цикле активности. Жизненный цикл — это набор состояний, в которых активность может находиться в течение всего своего существования, с момента ее создания до момента ее уничтожения и восстановления системой своих ресурсов. Когда пользователь перемещается между действиями в вашем приложении (а также между входами и выходами из вашего приложения), действия переходят из одного состояния в свой жизненный цикл.
Каждому этапу жизненного цикла активности соответствует соответствующий метод обратного вызова: onCreate(), onStart(), onPause() и т. д. Когда действие меняет состояние, вызывается соответствующий метод обратного вызова. Вы уже видели один из этих методов: onCreate(). Переопределяя любой из методов обратного вызова жизненного цикла в ваших классах активности, вы можете изменить поведение активности по умолчанию в ответ на действия пользователя или системы.
Состояние активности также может меняться в ответ на изменения конфигурации устройства, например, когда пользователь поворачивает устройство из книжной ориентации в альбомную. Когда происходят эти изменения конфигурации, действие уничтожается и воссоздается в состоянии по умолчанию, и пользователь может потерять информацию, которую он ввел в действие. Чтобы не вводить пользователей в заблуждение, важно разработать свое приложение таким образом, чтобы предотвратить непредвиденную потерю данных. Далее в этом практическом занятии вы поэкспериментируете с изменениями конфигурации и узнаете, как сохранять состояние действия в ответ на изменения конфигурации устройства и другие события жизненного цикла действия.
В этом практическом занятии вы добавите операторы журналирования в приложение TwoActivities и будете наблюдать за изменениями жизненного цикла действий по мере использования приложения. Затем вы начинаете работать с этими изменениями и изучать, как обрабатывать ввод пользователя в этих условиях.
Предварительные условия
Вы должны быть в состоянии:
- Создайте и запустите проект приложения в Android Studio .
- Добавьте операторы журнала в свое приложение и просматривайте эти журналы на панели Logcat.
- Понимайте и работайте с Действием и Намерением, а также будьте комфортно с ними взаимодействовать.
Что вы узнаете
- Как работает жизненный цикл Activity.
- Когда действие запускается, приостанавливается, останавливается и уничтожается.
- О методах обратного вызова жизненного цикла, связанных с изменениями активности.
- Эффект действий (например, изменений конфигурации), которые могут привести к событиям жизненного цикла действия.
- Как сохранить состояние активности во время событий жизненного цикла.
Что ты будешь делать
- Добавьте в приложение TwoActivities код из предыдущего практического занятия, чтобы реализовать различные обратные вызовы жизненного цикла активности и включить операторы журналирования.
- Наблюдайте за изменениями состояния при запуске вашего приложения и при взаимодействии с каждым действием в вашем приложении.
- Измените свое приложение, чтобы сохранить состояние экземпляра действия, которое неожиданно воссоздается в ответ на поведение пользователя или изменение конфигурации на устройстве.
2. Обзор приложения
В этом практическом занятии вы добавите приложение TwoActivities . Приложение выглядит и ведет себя примерно так же, как и в последней кодовой лаборатории. Он содержит две реализации Activity и дает пользователю возможность отправлять данные между ними. Изменения, которые вы внесете в приложение в этом практическом занятии, не повлияют на его видимое поведение пользователя.
3. 3. Задача 1. Добавьте обратные вызовы жизненного цикла в TwoActivities.
В этой задаче вы реализуете все методы обратного вызова жизненного цикла Activity для вывода сообщений в logcat при вызове этих методов. Эти сообщения журнала позволят вам увидеть, когда изменяется состояние жизненного цикла активности, и как эти изменения состояния жизненного цикла влияют на ваше приложение во время его работы.
1.1 (Необязательно) Скопируйте проект TwoActivities.
Для выполнения задач этого практического занятия вы измените существующий проект TwoActivities , который вы создали на последнем практическом занятии. Если вы предпочитаете сохранить предыдущий проект TwoActivities нетронутым, выполните действия, описанные в Приложении: Утилиты , чтобы сделать копию проекта.
1.2 Реализация обратных вызовов в MainActivity
- Откройте проект TwoActivities в Android Studio и откройте MainActivity на панели «Проект» > Android.
- В методе onCreate() добавьте следующие операторы журнала:
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
- Добавьте переопределение для обратного вызова onStart() с оператором в журнале для этого события:
@Override
public void onStart(){
super.onStart();
Log.d(LOG_TAG, "onStart");
}
Для ярлыка выберите «Код» > «Переопределить методы» в Android Studio. Появится диалоговое окно со всеми возможными методами, которые вы можете переопределить в своем классе. Выбор одного или нескольких методов обратного вызова из списка вставляет полный шаблон для этих методов, включая необходимый вызов суперкласса.
- Используйте метод onStart() в качестве шаблона для реализации обратных вызовов жизненного цикла onPause(), onRestart(), onResume(), onStop() и onDestroy().
Все методы обратного вызова имеют одинаковые сигнатуры (кроме имени). Если вы копируете и вставляете onStart() для создания этих других методов обратного вызова, не забудьте обновить содержимое, чтобы вызвать правильный метод в суперклассе и зарегистрировать правильный метод.
- Запустите свое приложение.
- Нажмите вкладку Logcat в нижней части Android Studio, чтобы отобразить панель Logcat. Вы должны увидеть три сообщения журнала, показывающие три состояния жизненного цикла, через которые прошло действие при запуске:
D/MainActivity: -------
D/MainActivity: onCreate
D/MainActivity: onStart
D/MainActivity: onResume
1.3 Реализация обратных вызовов жизненного цикла в SecondActivity
Теперь, когда вы реализовали методы обратного вызова жизненного цикла для MainActivity, сделайте то же самое для SecondActivity.
- Откройте SecondActivity.
- В верхней части класса добавьте константу для переменной LOG_TAG:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
- Добавьте обратные вызовы жизненного цикла и операторы журнала во второе действие. (Вы можете скопировать и вставить методы обратного вызова из MainActivity.)
- Добавьте оператор журнала в метод returnReply() непосредственно перед методом Finish():
Log.d(LOG_TAG, "End SecondActivity");
1.4. Просмотрите журнал во время работы приложения**
- Запустите свое приложение.
- Нажмите вкладку Logcat в нижней части Android Studio, чтобы отобразить панель Logcat.
- Введите «Активность» в поле поиска. Логарифм Android может быть очень длинным и запутанным. Поскольку переменная LOG_TAG в каждом классе содержит слова MainActivity или SecondActivity, это ключевое слово позволяет фильтровать журнал только по тем вещам, которые вас интересуют.
Поэкспериментируйте с приложением и обратите внимание, что события жизненного цикла происходят в ответ на различные действия. В частности, попробуйте следующее:
- Используйте приложение как обычно (отправьте сообщение, ответьте другим сообщением).
- Используйте кнопку «Назад», чтобы вернуться от второго действия к основному действию.
- Используйте стрелку вверх на панели приложения, чтобы вернуться от второго действия к основному действию.
- Вращайте устройство как в основной, так и во второй активности в разное время в вашем приложении и наблюдайте, что * происходит в журнале и на экране.
- Нажмите кнопку обзора (квадратная кнопка справа от «Домой») и закройте приложение (коснитесь X).
- Вернитесь на главный экран и перезапустите приложение.
СОВЕТ: Если вы запускаете приложение в эмуляторе, вы можете имитировать вращение с помощью Control+F11 или Control+Function+F11.
Код решения задачи 1
В следующих фрагментах кода показан код решения для первой задачи.
Основная деятельность
Следующие фрагменты кода показывают добавленный код в MainActivity, но не весь класс.
Метод onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Log the start of the onCreate() method.
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
}
Другие методы жизненного цикла:
@Override
protected void onStart() {
super.onStart();
Log.d(LOG_TAG, "onStart");
}
@Override
protected void onPause() {
super.onPause();
Log.d(LOG_TAG, "onPause");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(LOG_TAG, "onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(LOG_TAG, "onResume");
}
@Override
protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "onDestroy");
}
Вторая активность
В следующих фрагментах кода показан добавленный код в SecondActivity, но не весь класс.
В верхней части класса SecondActivity:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
Метод returnReply():
public void returnReply(View view) {
String reply = mReply.getText().toString();
Intent replyIntent = new Intent();
replyIntent.putExtra(EXTRA_REPLY, reply);
setResult(RESULT_OK, replyIntent);
Log.d(LOG_TAG, "End SecondActivity");
finish();
}
Другие методы жизненного цикла:
То же, что и для MainActivity выше.
4. 4. Задача 2. Сохраните и восстановите состояние экземпляра Activity.
В зависимости от системных ресурсов и поведения пользователя каждое действие в вашем приложении может уничтожаться и восстанавливаться гораздо чаще, чем вы думаете.
Возможно, вы заметили такое поведение в последнем разделе, когда поворачивали устройство или эмулятор. Поворот устройства является одним из примеров изменения конфигурации устройства. Хотя ротация является наиболее распространенной, все изменения конфигурации приводят к уничтожению текущего действия и его воссозданию, как если бы оно было новым. Если вы не учтете это поведение в своем коде, то при изменении конфигурации макет вашей активности может вернуться к внешнему виду и исходным значениям по умолчанию, а ваши пользователи могут потерять свое место, свои данные или состояние своего прогресса в работе. ваше приложение.
Состояние каждого действия хранится в виде набора пар ключ/значение в объекте Bundle, который называется состоянием экземпляра действия. Система сохраняет информацию о состоянии по умолчанию в пакете состояния экземпляра непосредственно перед остановкой действия и передает этот пакет новому экземпляру действия для восстановления.
Чтобы не потерять данные в действии при его неожиданном уничтожении и воссоздании, вам необходимо реализовать метод onSaveInstanceState(). Система вызывает этот метод для вашего действия (между onPause() и onStop()), когда существует вероятность того, что действие может быть уничтожено и воссоздано.
Данные, которые вы сохраняете в состоянии экземпляра, относятся только к этому экземпляру этого конкретного действия во время текущего сеанса приложения. Когда вы останавливаете и перезапускаете новый сеанс приложения, состояние экземпляра действия теряется, и действие возвращается к виду по умолчанию. Если вам нужно сохранять пользовательские данные между сеансами приложения, используйте общие настройки или базу данных. Вы узнаете об обоих из них на следующем практическом занятии.
2.1. Сохраните состояние экземпляра Activity с помощью onSaveInstanceState().
Возможно, вы заметили, что поворот устройства вообще не влияет на состояние второго Activity. Это связано с тем, что второй макет и состояние действия генерируются на основе макета и намерения, которое его активировало. Даже если действие создается заново, намерение все еще существует, и данные в этом намерении по-прежнему используются каждый раз, когда вызывается метод onCreate() во втором действии.
Кроме того, вы можете заметить, что в каждом действии любой текст, введенный вами в элементы EditText сообщения или ответа, сохраняется даже при повороте устройства. Это связано с тем, что информация о состоянии некоторых элементов представления в вашем макете автоматически сохраняется при изменении конфигурации, и текущее значение EditText является одним из таких случаев.
Таким образом, единственное состояние действия, которое вас интересует, — это элементы TextView для заголовка ответа и текст ответа в основном действии. Оба элемента TextView по умолчанию невидимы; они появляются только после того, как вы отправите сообщение обратно в основное действие из второго действия.
В этой задаче вы добавляете код для сохранения состояния экземпляра этих двух элементов TextView с помощью onSaveInstanceState().
- Откройте MainActivity.
- Добавьте эту скелетную реализацию onSaveInstanceState() в действие или используйте «Код» > «Методы переопределения», чтобы вставить переопределение скелета.
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
- Проверьте, виден ли в данный момент заголовок, и если да, поместите это состояние видимости в состояние Bundle с помощью метода putBoolean() и ключа «reply_visible».
if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
outState.putBoolean("reply_visible", true);
}
Помните, что заголовок и текст ответа помечаются как невидимые до тех пор, пока не будет получен ответ от второго действия. Если заголовок виден, значит, есть данные ответа, которые необходимо сохранить. Обратите внимание, что нас интересует только это состояние видимости — фактический текст заголовка не нужно сохранять, поскольку этот текст никогда не меняется.
- Внутри этой же проверки добавьте текст ответа в Bundle.
outState.putString("reply_text",mReplyTextView.getText().toString());
Если заголовок виден, вы можете предположить, что само ответное сообщение также видно. Вам не нужно проверять или сохранять текущее состояние видимости ответного сообщения. В состояние Bundle переходит только сам текст сообщения с ключом «reply_text».
Вы сохраняете состояние только тех элементов представления, которые могут измениться после создания действия. Другие элементы View в вашем приложении (EditText, Button) можно в любое время воссоздать из макета по умолчанию.
Обратите внимание, что система сохранит состояние некоторых элементов представления, например содержимого EditText.
2.2. Восстановите состояние экземпляра Activity в onCreate().
После того как вы сохранили состояние экземпляра действия, вам также необходимо восстановить его при повторном создании действия. Вы можете сделать это либо в onCreate(), либо реализовав обратный вызов onRestoreInstanceState(), который вызывается после onStart() после создания действия.
В большинстве случаев лучшим местом для восстановления состояния активности является onCreate(), чтобы гарантировать, что пользовательский интерфейс, включая состояние, будет доступен как можно скорее. Иногда удобно сделать это в onRestoreInstanceState() после завершения всей инициализации или позволить подклассам решить, использовать ли вашу реализацию по умолчанию.
- В методе onCreate() после инициализации переменных View с помощью findViewById() добавьте тест, чтобы убедиться, что saveInstanceState не имеет значения null.
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
// Restore the state.
if (savedInstanceState != null) {
}
Когда ваша активность создается, система передает состояние Bundle в onCreate() в качестве единственного аргумента. При первом вызове onCreate() и запуске вашего приложения Bundle имеет значение null — при первом запуске вашего приложения никакого существующего состояния не существует. При последующих вызовах onCreate() пакет заполняется данными, которые вы сохранили в onSaveInstanceState().
- Внутри этой проверки получите текущую видимость (истину или ложь) из пакета с помощью ключа «reply_visible».
if (savedInstanceState != null) {
boolean isVisible =
savedInstanceState.getBoolean("reply_visible");
}
- Добавьте тест ниже предыдущей строки для переменной isVisible.
if (isVisible) {
}
Если в состоянии Bundle есть ключ response_visible (и, следовательно, isVisible имеет значение true), вам потребуется восстановить состояние.
- Внутри теста isVisible сделайте заголовок видимым.
mReplyHeadTextView.setVisibility(View.VISIBLE);
- Получите текстовое ответное сообщение из пакета с ключом «reply_text» и настройте TextView ответа на отображение этой строки.
mReplyTextView.setText(savedInstanceState.getString("reply_text"));
- Сделайте также ответ TextView видимым:
mReplyTextView.setVisibility(View.VISIBLE);
- Запустите приложение. Попробуйте повернуть устройство или эмулятор, чтобы ответное сообщение (если оно есть) оставалось на экране после воссоздания действия.
Код решения задачи 2
В следующих фрагментах кода показан код решения для этой задачи.
Основная деятельность
Следующие фрагменты кода показывают добавленный код в MainActivity, но не весь класс.
Метод onSaveInstanceState():
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// If the heading is visible, message needs to be saved.
// Otherwise we're still using default layout.
if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
outState.putBoolean("reply_visible", true);
outState.putString("reply_text",
mReplyTextView.getText().toString());
}
}
Метод onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
// Restore the saved state.
// See onSaveInstanceState() for what gets saved.
if (savedInstanceState != null) {
boolean isVisible =
savedInstanceState.getBoolean("reply_visible");
// Show both the header and the message views. If isVisible is
// false or missing from the bundle, use the default layout.
if (isVisible) {
mReplyHeadTextView.setVisibility(View.VISIBLE);
mReplyTextView.setText(savedInstanceState
.getString("reply_text"));
mReplyTextView.setVisibility(View.VISIBLE);
}
}
}
Полный проект:
Проект Android Studio: TwoActivitiesLifecycle
5. Кодирование
Задача: создать простое приложение со списком покупок с основным действием для списка, который создает пользователь, и вторым действием для списка распространенных товаров для покупок.
- Основное действие должно содержать список для построения, который должен состоять из десяти пустых элементов TextView.
- Кнопка «Добавить товар» в основном действии запускает второе действие, содержащее список распространенных товаров для покупок (сыр, рис, яблоки и т. д.). Используйте элементы Button для отображения элементов.
- Выбор элемента возвращает пользователя к основному действию и обновляет пустой TextView, включив в него выбранный элемент.
Используйте намерение для передачи информации из одного действия в другое. Убедитесь, что текущее состояние списка покупок сохраняется, когда пользователь поворачивает устройство.
6. Резюме
- Жизненный цикл действия — это набор состояний, через которые проходит действие, начиная с момента его первого создания и заканчивая моментом, когда система Android восстанавливает ресурсы для этого действия.
- Когда пользователь переходит от одного действия к другому, внутри и снаружи вашего приложения, каждое действие перемещается между состояниями жизненного цикла действия.
- Каждое состояние жизненного цикла Activity имеет соответствующий метод обратного вызова, который вы можете переопределить в своем классе Activity.
- Методами жизненного цикла являются onCreate(), onStart(), onPause(), onRestart(), onResume(), onStop(), onDestroy().
- Переопределение метода обратного вызова жизненного цикла позволяет вам добавить поведение, которое происходит, когда ваше действие переходит в это состояние.
- Вы можете добавить методы переопределения скелета в свои классы в Android Studio, выбрав «Код» > «Переопределить».
- Изменения конфигурации устройства, такие как ротация, приводят к уничтожению и воссозданию действия, как если бы оно было новым.
- Часть состояния Activity сохраняется при изменении конфигурации, включая текущие значения элементов EditText. Для всех остальных данных вы должны явно сохранить эти данные самостоятельно.
- Сохраните состояние экземпляра Activity в методе onSaveInstanceState().
- Данные о состоянии экземпляра хранятся в виде простых пар ключ/значение в пакете. Используйте методы Bundle для помещения данных в Bundle и получения данных обратно из него.
- Восстановите состояние экземпляра с помощью onCreate() (предпочтительный способ) или onRestoreInstanceState(). Назад