Сохранение состояния фрагментами,Сохранение состояния фрагментами

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

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

  • Переменные: локальные переменные во фрагменте.
  • Состояние представления: любые данные, принадлежащие одному или нескольким представлениям во фрагменте.
  • SavedState: данные, присущие этому экземпляру фрагмента, которые следует сохранить в onSaveInstanceState() .
  • NonConfig: данные, полученные из внешнего источника, например сервера или локального репозитория, или созданные пользователем данные, которые отправляются на сервер после фиксации.

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

Операция Переменные Просмотр состояния Саведстате Неконфигурируемый
Добавлено в задний стек х
Изменение конфигурации х
Процесс смерти/воссоздания х ✓*
Удален, не добавлен в задний стек х х х х
Хост завершен х х х х

* Состояние NonConfig можно сохранить после смерти процесса с помощью модуля Saved State для ViewModel .

Таблица 1: Различные операции по разрушению фрагментов и их влияние на разные типы состояний.

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

приложение-генератор случайного текста, которое демонстрирует различные типы состояний
Рис. 1. Приложение-генератор случайного текста, демонстрирующее различные типы состояний.

В этом примере предположим, что как только пользователь нажимает кнопку редактирования, приложение отображает представление EditText , в котором пользователь может редактировать сообщение. Если пользователь нажимает CANCEL , представление EditText должно быть очищено, а его видимость установлена ​​на View.GONE . Для обеспечения бесперебойной работы такого экрана может потребоваться управление четырьмя частями данных:

Данные Тип Тип государства Описание
seed Long Неконфигурируемый Семя, используемое для случайного создания нового доброго дела. Создается при создании ViewModel .
randomGoodDeed String Сохраненное состояние + переменная Генерируется при первом создании фрагмента. randomGoodDeed сохраняется, чтобы гарантировать, что пользователи увидят одно и то же случайное доброе дело даже после смерти и воссоздания процесса.
isEditing Boolean Сохраненное состояние + переменная Логический флаг устанавливается в значение true , когда пользователь начинает редактирование. isEditing сохраняется, чтобы гарантировать, что редактируемая часть экрана останется видимой при воссоздании фрагмента.
Отредактированный текст Editable Состояние просмотра (принадлежит EditText ) Отредактированный текст в представлении EditText . Представление EditText сохраняет этот текст, чтобы гарантировать, что текущие изменения пользователя не будут потеряны.

Таблица 2: Указывает, что приложение генератора случайного текста должно управлять.

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

Посмотреть состояние

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

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

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

<EditText
    android:id="@+id/good_deed_edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

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

SavedState

Ваш фрагмент отвечает за управление небольшими объемами динамического состояния, которые являются неотъемлемой частью функционирования фрагмента. Вы можете сохранить легко сериализуемые данные, используя Fragment.onSaveInstanceState(Bundle) . Подобно Activity.onSaveInstanceState(Bundle) данные, которые вы помещаете в пакет, сохраняются при изменениях конфигурации, а также смерти и воссоздании процесса и доступны в onCreate(Bundle) вашего фрагмента, onCreateView(LayoutInflater, ViewGroup, Bundle) и onViewCreated(View, Bundle) методы.

Продолжая предыдущий пример, randomGoodDeed — это документ, который отображается пользователю, а isEditing — это флаг, определяющий, показывает или скрывает фрагмент EditText . Это сохраненное состояние следует сохранить с помощью onSaveInstanceState(Bundle) , как показано в следующем примере:

Котлин

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putBoolean(IS_EDITING_KEY, isEditing)
    outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed)
}

Ява

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean(IS_EDITING_KEY, isEditing);
    outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed);
}

Чтобы восстановить состояние в onCreate(Bundle) извлеките сохраненное значение из пакета:

Котлин

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    isEditing = savedInstanceState?.getBoolean(IS_EDITING_KEY, false)
    randomGoodDeed = savedInstanceState?.getString(RANDOM_GOOD_DEED_KEY)
            ?: viewModel.generateRandomGoodDeed()
}

Ява

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        isEditing = savedInstanceState.getBoolean(IS_EDITING_KEY, false);
        randomGoodDeed = savedInstanceState.getString(RANDOM_GOOD_DEED_KEY);
    } else {
        randomGoodDeed = viewModel.generateRandomGoodDeed();
    }
}

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

Неконфигурируемый

Данные NonConfig следует размещать за пределами вашего фрагмента, например, в ViewModel . В предыдущем примере выше seed (наше состояние NonConfig) генерируется в ViewModel . Логика поддержания его состояния принадлежит ViewModel .

Котлин

public class RandomGoodDeedViewModel : ViewModel() {
    private val seed = ... // Generate the seed

    private fun generateRandomGoodDeed(): String {
        val goodDeed = ... // Generate a random good deed using the seed
        return goodDeed
    }
}

Ява

public class RandomGoodDeedViewModel extends ViewModel {
    private Long seed = ... // Generate the seed

    private String generateRandomGoodDeed() {
        String goodDeed = ... // Generate a random good deed using the seed
        return goodDeed;
    }
}

Класс ViewModel по своей сути позволяет данным сохраняться при изменении конфигурации, например повороте экрана, и оставаться в памяти, когда фрагмент помещается в задний стек. После смерти и воссоздания процесса ViewModel создается заново и создается новое seed . Добавление модуля SavedState в вашу ViewModel позволяет ViewModel сохранять простое состояние даже при прекращении и воссоздании процесса.

Дополнительные ресурсы

Дополнительные сведения об управлении состоянием фрагмента см. в следующих дополнительных ресурсах.

Кодлабы

Путеводители