Czym różnią się operacje popBackStack() i replace ()?

Napotkałem pewne dziwne zachowanie w mojej aplikacji podczas zarządzania fragmentami i zastanawiałem się, czy tak może pomóc rzucić trochę światła na to, dlaczego tak się dzieje.

Mam dwa fragmenty, nazwiemy je Fragment A i Fragment B. ogólny przebieg mojej aplikacji polega na tym, że gdy użytkownik w jakiś sposób wchodzi w interakcję z fragmentem A, Fragment B jest pokazywany przez wywołanie fragmentTransaction.replace() (dzieje się tak we wszystkich przypadkach). Kiedy pokazuję Fragment B, dodaję Fragment A do tylnego stosu; następnie, gdy użytkownik naciska przycisk back na fragmencie B, Fragment A zostaje ponownie pokazany poprzez Wyskakiwanie z tylnego stosu.

To wszystko dobrze i dobrze, ale dzisiaj odkryłem, że istnieje przepływ z fragmentu B, który wywołuje fragmentTransaction.replace(), zastępując Fragment B tą samą instancją fragmentu A, która jest obecnie na tylnym stosie.

Sama w sobie nie ma w tym nic złego, jednak dziwne zachowanie powstaje, gdy wracam z fragmentu A do fragmentu B. Jeśli wywołałem fragmentTransaction.replace(), metoda onCreate() fragmentu B nie jest wezwany.

Jednakże, jeśli wyrwałem Fragment A z tylnego stosu, a następnie zamieniłem go na Fragment B, zostanie wywołana metoda onCreate() fragmentu B. Dlaczego?

Zauważ, że wszystkie instancje fragmentu A i fragmentu B są tworzone w momencie uruchomienia ich aktywności hosta.

Edycja dla wyjaśnienia. Przypadek, w którym onCreate() jest wywoływany po raz drugi, jest następujący: Załącz Fragment A = > zastąp fragmentem B, dodając Fragment A do tylnego stosu = > pop Fragment A używając popBackStack() = > zamień ponownie Fragment A na Fragment B.

Author: Jonathan, 2013-07-22

2 answers

replace() Czy 2 rzeczy:

  1. Usuń aktualnie dodany fragment (a) ze wskazanego przez Ciebie kontenera (C)
  2. Dodaj nowy fragment (B) do tego samego kontenera

Te 2 operacje są zapisywane jako rekord Backstack / transakcja. Zauważ, że fragment A pozostaje w stanie created, a jego widok jest zniszczony.

Teraz popBackStack() odwraca ostatnią transakcję dodaną do Backstacka.

W tym przypadku byłoby to 2 kroki:

  1. Usuń B z C
  2. Dodaj A do C

Po tym fragment B staje się detached, a jeśli nie zachowasz odniesień do niego, będzie to śmieci zebrane.

Aby odpowiedzieć na pierwszą część twojego pytania, nie ma onCreate() wywołania, ponieważ FragmentB pozostał w created stanie. A odpowiedź na drugą część pytania jest nieco dłuższa.

Po pierwsze, ważne jest, aby zrozumieć, że nie dodajesz Fragments do Backstacka, dodajesz FragmentTransactions. Więc kiedy ty pomyśl, że "zamieniasz Fragment B, dodając Fragment A do tylnego stosu", w rzeczywistości dodajesz całą tę operację do backstacka - czyli zastąpienie A przez B. Ten zastąpienie składa się z 2 akcji - usuń a i dodaj B.

Następnie, następnym krokiem jest wyskakiwanie transakcji, która zawiera ten zamiennik. Więc nie wyskakujesz FragmentA, tylko odwracasz "usuń A, dodaj B", co odwrócone jest "Usuń B, Dodaj a".

I wtedy ostatni krok powinien być jaśniejszy - nie ma B jest świadomy tego FragmentManager, więc kiedy dodasz go, zastępując A na B w ostatnim kroku, B musi przejść przez swoje wczesne metody cyklu życia - onAttach() i onCreate().

Poniższy kod ilustruje, co się dzieje.

FragmentManager fm  = getFragmentManager();
FragmentA fragmentA = new FragmentA();
FragmentB fragmentB = new FragmentB();

// 1. Show A
fm.beginTransaction()
  .add(fragmentA, R.id.container)
  .commit();

// 2. Replace A with B
// FragmentManager keeps reference to fragmentA;
// it stays attached and created; fragmentB goes 
// through lifecycle methods onAttach(), onCreate()
// and so on.
fm.beginTransaction()
  .replace(fragmentB, R.id.container)
  .addToBackstack(null)
  .commit();

// 2'. Alternative to replace() method
fm.beginTransaction()
  .remove(fragmentA)
  .add(fragmentB, R.id.container)
  .addToBackstack(null)
  .commit();

// 3. Reverse (2); Result - A is visible
// What happens:
//   1) fragmentB is removed from container, it is detached now;
//      FragmentManager doesn't keep reference to it anymore
//   2) Instance of FragmentA is placed back in the container
// Now your Backstack is empty, FragmentManager is aware only
// of FragmentA instance
fm.popBackStack();

// 4. Show B
// Since fragmentB was detached, it goes through its early
// lifecycle methods: onAttach() and onCreate().
fm.beginTransaction()
  .replace(fragmentB, R.id.container)
  .addToBackstack(null)
  .commit();
 71
Author: mindeh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-22 20:02:11

Może dlatego, że menedżer fragmentów używa ponownie instancji fragmentu, a raczej ją odtwarza. Jeśli kod wewnątrz fragmentu B onCreate() wymaga wykonania podczas pokazywania fragmentu, przenieś kod w inną metodę, taką jak onResume().

 0
Author: tbruyelle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-22 17:28:29