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.
2 answers
replace()
Czy 2 rzeczy:
- Usuń aktualnie dodany fragment (a) ze wskazanego przez Ciebie kontenera (C)
- 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:
- Usuń B z C
- 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();
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()
.
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