change - restore state fragment android



come posso spezzare le cose con Fragments con setRetainInstance(true) e aggiungerle a backstack? (1)

Risposta aggiornata:

Quali sono gli scenari in cui potrei finire nei guai?

Quando si aggiunge un Fragment allo stack posteriore e si passa un Bundle nel Fragment da onSaveInstanceState() a onCreateView() sulla modifica della configurazione. La chiamata a setRetainInstance(true) imposterà il Bundle nullo alla modifica della configurazione.

(Non sono sicuro che uno sviluppatore potrebbe tentare di setRetainInstance(true) poiché usare setRetainInstance(true) rende onSaveInstanceState() sorta di ridondante, ma non ho visto il comportamento documentato nei documenti API così ho scritto questa risposta).

Se vengono addToBackStack() sia addToBackStack() che setRetainInstance(true) , setRetainInstance() modifica in parte le chiamate del metodo del ciclo di vita Fragment e i valori dei parametri nelle modifiche di configurazione, rispetto a chiamare solo addToBackStack() .

Nello specifico, nel test seguente, osservando le differenze tra chiamare solo addToBackStack() e chiamare setRetainInstance(true) , e vedere cosa succede nella modifica della configurazione:

Chiamando addToBackStack() ma non setRetainInstance(true) ;

  • onCreate() e onDestroy() sono chiamati.
  • un pacchetto passato da onSaveInstanceState() viene ricevuto come parametro in onCreateView() .

Chiamando sia addToBackStack() che setRetainInstance(true) :

  • onCreate() e onDestroy() non vengono chiamati. Questo è indicato nei documenti API.
  • un bundle trasmesso da onSaveInstanceState() non viene ricevuto in onCreateView() . Il Bundle passato è nullo.

Un test con le chiamate dei metodi registrati e i parametri testati per null:

Nell'attività:

@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(); 
    }
}

Nel Fragment :

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

e

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

Test 1: addToBackStack() vita dei frammenti quando viene chiamato addToBackStack() e setRetainInstance(true) non viene chiamato

  • onAttach ()
  • onCreate ()
  • onCreateView ()
  • onActivityCreated ()
  • onStart ()
  • onResume ()

[Dispositivo ruotato da verticale a orizzontale]

  • onPause ()
  • onSaveInstanceState ()
  • onStop ()
  • onDestroyView ()
  • OnDestroy ()
  • onDetach ()
  • onAttach ()
  • onCreate ()
  • onCreateView () con bundle param! = null
  • onStart ()
  • onResume ()

Test 2 e 3: chiamate del ciclo di vita dei frammenti con setRetainInstance(true) chiamato, addToBackStack() chiamato / non chiamato (stesso risultato):

  • onAttach ()
  • onCreateView ()
  • onActivityCreated ()
  • onStart ()
  • onResume ()

[Dispositivo ruotato da verticale a orizzontale]

  • onPause ()
  • onSaveInstanceState ()
  • onStop ()
  • onDestroyView ()
  • onDetach ()
  • onAttach ()
  • onCreateView () con il parametro bund == null
  • onStart ()
  • onResume ()

i documenti su setRetainInstance dicono:

Questo può essere usato solo con frammenti non nello stack posteriore.

così ho iniziato a giocarci.

Ho un'attività con l'aggiunta del primo frammento A

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

quindi da questo frammento eseguo un metodo da Parent Activity che aggiunge frag B allo backstack

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

quindi creo i messaggi di log da onCreate, onDestroy, onSaveInstanceState, onActivityCreated ... ecc.

Provo due versioni di questo processo. Rotazione del dispositivo su ciascun frammento.

  1. predefinito

Tutto è come previsto onCreate, onDestroy su frammenti di fuoco

  1. setRetainInstance (vero)

Tutto è come previsto ?. onCreate, onDestroy su frammenti non si accende

e tutto sembra funzionare mentre i frammenti sono nel backstack .. quindi perché i documenti dicono che non dovrei usarlo? Quali sono gli scenari in cui potrei finire nei guai?

Grazie





android-orientation