Как я могу сломать вещи с помощью фрагментов с помощью setRetainInstance (true) и добавить их в backstack?

документы на setRetainInstance говорят:

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

поэтому я начал играть с ним.

У меня есть одно действие с добавлением первого фрагмента A

FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.content, new PackageFragment());
ft.commit

то из этого фрагмента я запускаю метод из родительской активности, который добавляет frag B в backstack

FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.content, new OrderFragment());
ft.addToBackStack(null);
ft.commit();

то я создаю log msg из onCreate, onDestroy, onSaveInstanceState, onActivityCreated... и т.д.

Я пробую две версии этого процесса. Поворот устройства на каждый фрагмент.

  • По умолчанию

Все так, как ожидалось. onCreate, onDestroy on fragments fire

  • setRetainInstance (истина)

Все как ожидалось?. onCreate, onDestroy на фрагментах не огонь

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

спасибо

Ответ 1

Обновленный ответ:

Каковы сценарии, в которых я могу попасть в беду?

При добавлении Fragment в задний стек и передачи Bundle в Fragment от onSaveInstanceState() до onCreateView() при изменении конфигурации. Вызов setRetainInstance(true) установит для параметра Bundle значение null при изменении конфигурации.

(я не уверен, что разработчик действительно попытался бы это сделать, поскольку использование setRetainInstance(true) делает onSaveInstanceState() избыточным, но я не видел поведения, задокументированного в документах API, поэтому я написал этот ответ).

Если вызываются как addToBackStack(), так и setRetainInstance(true), setRetainInstance() частично изменяет вызовы метода жизненного цикла Fragment и значения параметров при изменениях конфигурации по сравнению с вызывающим только addToBackStack().

В частности, в нижеприведенном тесте, рассматривая различия между вызовом только addToBackStack() и вызовом setRetainInstance(true), и выясняя, что происходит при изменении конфигурации:

Вызов addToBackStack(), но не setRetainInstance(true);

  • onCreate() и onDestroy().
  • пучок, переданный из onSaveInstanceState(), принимается как параметр в onCreateView().

Вызов как addToBackStack(), так и setRetainInstance(true):

  • onCreate() и onDestroy() не вызываются. Это подтверждается документами API.
  • пучок, переданный из onSaveInstanceState(), не получен в onCreateView(). Переданный Bundle имеет значение null.

Тест с зарегистрированными вызовами метода и параметрами, проверенными на null:

В Activity:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    MyFragment fragment;
    if (savedInstanceState != null) {
        fragment = (MyFragment) getFragmentManager().findFragmentByTag("my_fragment_tag");
    } else {
        fragment = new MyFragment();
        FragmentTransaction t = getFragmentManager().beginTransaction();
        t.addToBackStack(null);//toggle this
        t.add(android.R.id.content, fragment, "my_fragment_tag").commit(); 
    }
}

В Fragment:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setRetainInstance(true);//toggle this
}

и

@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString("test", "value");
    super.onSaveInstanceState(outState);
}

Тест 1: жизненный цикл фрагмента при вызове addToBackStack(), а setRetainInstance(true) - not, называемый

  • onAttach()
  • OnCreate()
  • onCreateView()
  • onActivityCreated()
  • OnStart()
  • onResume()

[Устройство повернуто от портрета к пейзажу]

  • OnPause()
  • onSaveInstanceState()
  • OnStop()
  • onDestroyView()
  • OnDestroy()
  • onDetach()
  • onAttach()
  • OnCreate()
  • onCreateView() с пакетом param!= null
  • OnStart()
  • onResume()

Тестирование 2 и 3: вызовы жизненного цикла фрагмента с вызываемым setRetainInstance(true), addToBackStack() вызванным/не вызываемым (тот же результат):

  • onAttach()
  • onCreateView()
  • onActivityCreated()
  • OnStart()
  • onResume()

[Устройство повернуто от портрета к пейзажу]

  • OnPause()
  • onSaveInstanceState()
  • OnStop()
  • onDestroyView()
  • onDetach()
  • onAttach()
  • onCreateView() с пакетом param == null
  • OnStart()
  • onResume()