Mam problem z tym, aby moje fragmenty komunikowały się ze sobą za pomocą Activity
, która używa FragmentPagerAdapter
klasy pomocniczej, która implementuje zarządzanie zakładkami i wszystkimi szczegółami łączenia się ViewPager
z powiązanymi TabHost
. Zaimplementowałem FragmentPagerAdapter
dokładnie to samo, co zapewnia przykładowy projekt Android Support4Demos .
Główne pytanie brzmi: jak mogę uzyskać określony fragment, FragmentManager
skoro nie mam ani identyfikatora, ani tagu? FragmentPagerAdapter
tworzy fragmenty i automatycznie generuje identyfikator i tagi.
android
android-fragments
fragmentpageradapter
Ismar Slomic
źródło
źródło
Odpowiedzi:
Podsumowanie problemu
Uwaga: w tej odpowiedzi zamierzam odwołać się do
FragmentPagerAdapter
kodu źródłowego. Ale ogólne rozwiązanie powinno również dotyczyćFragmentStatePagerAdapter
.Jeśli to czytasz, prawdopodobnie już wiesz, że
FragmentPagerAdapter
/FragmentStatePagerAdapter
ma tworzyćFragments
dla CiebieViewPager
, ale po odtworzeniu aktywności (czy to z obrotu urządzenia, czy systemu zabijającego aplikację w celu odzyskania pamięci)Fragments
, nie zostaną one ponownie utworzone, ale zamiast tego ich wystąpienia pobrane zFragmentManager
. Teraz powiedz, żeActivity
potrzebujesz odniesienia do nich,Fragments
aby nad nimi pracować. Nie maszid
anitag
dla tych utworzonych,Fragments
ponieważFragmentPagerAdapter
ustawisz je wewnętrznie . Problem polega więc na tym, jak uzyskać do nich odniesienie bez tych informacji ...Problem z obecnymi rozwiązaniami: poleganie na kodzie wewnętrznym
Wiele rozwiązań widziałem na tej i podobnych pytań polegać na coraz odniesienie do istniejącego
Fragment
dzwoniącFragmentManager.findFragmentByTag()
i imitując utworzony wewnętrznie tag:"android:switcher:" + viewId + ":" + id
. Problem polega na tym, że polegasz na wewnętrznym kodzie źródłowym, który, jak wszyscy wiemy, nie gwarantuje, że pozostanie taki sam na zawsze. Inżynierowie Androida w Google mogliby z łatwością zdecydować o zmianietag
struktury, która zepsułaby Twój kod, uniemożliwiając znalezienie odniesienia do istniejącegoFragments
.Alternatywne rozwiązanie bez polegania na wewnętrznym
tag
Oto prosty przykład, jak uzyskać odwołanie do
Fragments
zwróconego przezFragmentPagerAdapter
to elementu , który nie opiera się na wewnętrznymtags
zestawieFragments
. Kluczem jest nadpisanieinstantiateItem()
i zapisanie odwołań tam zamiast wgetItem()
.lub jeśli wolisz pracować ze
tags
zmiennymi składowymi / odwołaniami do klasy zamiast ze zmiennymi składowymiFragments
, możesz również pobraćtags
zestawFragmentPagerAdapter
w ten sam sposób: UWAGA: nie dotyczy to,FragmentStatePagerAdapter
ponieważ nie jest ustawianetags
podczas tworzeniaFragments
.Zauważ, że ta metoda NIE polega na naśladowaniu wewnętrznego
tag
zestawu przezFragmentPagerAdapter
i zamiast tego używa odpowiednich interfejsów API do ich pobierania. W ten sposób, nawet jeślitag
zmiany w przyszłych wersjachSupportLibrary
nadal będą bezpieczne.Nie zapominaj, że w zależności od projektu
Activity
, nadFragments
którym próbujesz pracować, może jeszcze istnieć lub nie, więc musisz to uwzględnić,null
sprawdzając przed użyciem referencji.Ponadto, jeśli zamiast tego pracujesz
FragmentStatePagerAdapter
, nie chcesz przechowywać twardych odniesień do swoich,Fragments
ponieważ możesz ich mieć wiele, a twarde odniesienia niepotrzebnie zatrzymałyby je w pamięci. Zamiast tego zapisujFragment
odwołania wWeakReference
zmiennych zamiast standardowych. Lubię to:źródło
instantiateItem
. właściwy sposób to zrobić, aby zadzwonićinstantiateItem
wonCreate
sposobie swoją działalność w otoczeniustartUpdate
ifinishUpdate
. Zobacz moją odpowiedź po szczegółyZnalazłem odpowiedź na swoje pytanie w oparciu o następujący post: ponowne wykorzystanie fragmentów w fragmentpageradapter
Kilka rzeczy, których się nauczyłem:
getItem(int position)
wFragmentPagerAdapter
to raczej myląca nazwa tego, co ta metoda faktycznie robi. Tworzy nowe fragmenty, nie zwracając istniejących. W związku z tym należy zmienić nazwę metody na podobnącreateItem(int position)
do zestawu Android SDK. Więc ta metoda nie pomaga nam w zdobywaniu fragmentów.FragmentPagerAdapter
co oznacza, że nie masz odniesienia do fragmentów ani ich tagów. Jeśli jednak masz znacznik fragmentu, możesz łatwo pobrać do niego odniesienie zFragmentManager
pliku, wywołującfindFragmentByTag()
. Potrzebujemy sposobu, aby znaleźć tag fragmentu w danej pozycji na stronie.Rozwiązanie
Dodaj następującą metodę pomocnika w swojej klasie, aby pobrać znacznik fragmentu i wysłać go do
findFragmentByTag()
metody.UWAGA! Jest to identyczna metoda, której
FragmentPagerAdapter
używa się przy tworzeniu nowych fragmentów. Zobacz ten link http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104źródło
onAttach()
?nie musisz nadpisywać
instantiateItem
ani polegać na zgodności z wewnętrznąmakeFragmentName
metodą poprzez ręczne tworzenie znaczników fragmentów.instantiateItem
jest metodą publiczną , więc możesz i faktycznie powinieneś ją wywoływać wonCreate
metodzie swojej aktywności otoczonej wywołaniamistartUpdate
ifinishUpdate
metodami, jak opisano wPagerAdapter
javadoc :W ten sposób, przy okazji, możesz przechowywać odniesienia do instancji swoich fragmentów na lokalnych zmiennych, jeśli potrzebujesz. Zobacz przykład:
instantiateItem
najpierw spróbuje pobrać odniesienia do istniejących instancji fragmentów z plikuFragmentManager
. Tylko jeśli jeszcze nie istnieją, utworzy nowe za pomocągetItem
metody z twojego adaptera i " " je wFragmentManager
celu wykorzystania w przyszłości.Ważne jest, aby pamiętać, że nawet jeśli nie musisz uzyskiwać referencji do swoich fragmentów, nadal powinieneś wywoływać
instantiateItem
wszystkie swoje karty otoczonestartUpdate
/finishUpdate
w swojejonCreate
metodzie w następujący sposób:Jeśli nie zrobić tak, to ryzykujesz, że instancje fragment nigdy nie będzie zobowiązana do
FragmentManager
: gdy czynność staje się pierwszym planieinstantiateItem
będzie wywoływana automatycznie, aby uzyskać swoje fragmenty, alestartUpdate
/finishUpdate
może nie (w zależności od szczegółów implementacji) i co w zasadzie do to rozpocząć / zatwierdzićFragmentTransaction
.Może to spowodować, że odniesienia do utworzonych instancji fragmentów zostaną bardzo szybko utracone (na przykład podczas obrócenia ekranu) i odtworzone znacznie częściej niż to konieczne. W zależności od tego, jak „ciężkie” są Twoje fragmenty, może to mieć niebagatelne konsekwencje dla wydajności. Ponadto w takich przypadkach fragmenty są przechowywane na lokalnych varach z jakiegokolwiek powodu się nie powieść, a tym samym utworzy i użyje nowych, podczas gdy twoje vary nadal będą odnosić się do starych.
mogą wystąpićstarzeją się: jeśli platforma Android spróbuje je z
FragmentManager
źródło
FragmentManager
nie może po prostu losowo zabić ( zniszczyć to właściwe słowo tutaj) twojegoFragment
(pomyśl, co by się stało, gdyby zdecydował się zabićFragment
aktualnie wyświetlany;)). Zasadniczo cykl życia aFragment
jest powiązany z jegoActivity
(szczegóły na github.com/xxv/android-lifecycle ) -> aFragment
można zniszczyć tylko wtedy, gdyActivity
zostało zniszczone. W takim przypadku, gdy do nawigacji użytkownika z powrotem na danyActivity
jejonCreate
zostanie wywołana ponownie i nowa instancjaFragment
zostanie utworzona.Sposób, w jaki to zrobiłem, polega na zdefiniowaniu tablicy haszowania słabych referencji w następujący sposób:
Następnie napisałem metodę getItem () w następujący sposób:
Następnie możesz napisać metodę:
Wydaje się, że działa dobrze i uważam, że jest trochę mniej skomplikowany niż
sztuczka, ponieważ nie polega na sposobie implementacji FragmentPagerAdapter. Oczywiście, jeśli fragment został wydany przez FragmentPagerAdapter lub nie został jeszcze utworzony, getFragment zwróci wartość null.
Jeśli ktoś zauważy coś złego w tym podejściu, komentarze są mile widziane.
źródło
int fragmentId
powinien zostać zmieniony naint position
Stworzyłem tę metodę, która działa dla mnie, aby uzyskać odniesienie do bieżącego fragmentu.
źródło
rozwiązanie zasugerowane przez @ personne3000 jest fajne, ale ma jeden problem: gdy aktywność przechodzi w tło i zostaje zabita przez system (aby uzyskać wolną pamięć), a następnie przywrócona,
fragmentReferences
będzie pusta, ponieważgetItem
nie byłoby nazywa.Poniższa klasa radzi sobie z taką sytuacją:
źródło
Główną przeszkodą w uzyskaniu uchwytu do fragmentów jest to, że nie można polegać na getItem (). Po zmianie orientacji odwołania do fragmentów będą miały wartość null i funkcja getItem () nie będzie ponownie wywoływana.
Oto podejście, które nie polega na implementacji FragmentPagerAdapter w celu pobrania tagu. Zastąp instancję instantiateItem (), która zwróci fragment utworzony przez getItem () lub znaleziony w menedżerze fragmentów.
źródło
Zobacz ten wpis dotyczący zwracania fragmentów z FragmentPagerAdapter. Czy polega na tym, że znasz indeks swojego fragmentu - ale zostanie to ustawione w getItem () (tylko podczas tworzenia instancji)
źródło
Udało mi się rozwiązać ten problem, używając identyfikatorów zamiast tagów. (Używam zdefiniowanego FragmentStatePagerAdapter, który używa moich niestandardowych fragmentów, w których nadpisuję metodę onAttach, gdzie gdzieś zapisujesz identyfikator:
A potem po prostu uzyskujesz łatwy dostęp do fragmentu w działaniu:
źródło
Nie wiem, czy to najlepsze podejście, ale nic innego nie zadziałało. Wszystkie inne opcje, w tym getActiveFragment, zwróciły wartość null lub spowodowały awarię aplikacji.
Zauważyłem, że podczas obracania ekranu fragment był dołączany, więc użyłem go do wysłania fragmentu z powrotem do ćwiczenia.
We fragmencie:
Następnie w ćwiczeniu:
I wreszcie w działaniu onCreate ():
Takie podejście łączy rzeczywisty widoczny fragment z działaniem bez tworzenia nowego.
źródło
Nie jestem pewien, czy moja metoda była poprawna lub najlepsza, ponieważ jestem stosunkowo początkującym użytkownikiem Java / Android, ale zadziałała (jestem pewien, że narusza zasady obiektowe, ale żadne inne rozwiązanie nie działało w moim przypadku użycia).
Miałem działanie hostingowe, które używało ViewPager z FragmentStatePagerAdapter. Aby uzyskać odniesienia do fragmentów, które zostały utworzone przez FragmentStatePagerAdapter, stworzyłem interfejs wywołania zwrotnego w klasie fragmentu:
W działalności hostingowej zaimplementowałem interfejs i stworzyłem LinkedHasSet do śledzenia fragmentów:
W klasie ViewPagerFragment dodałem fragmenty do listy w onAttach i usunąłem je w onDetach:
W ramach działania hostingu będziesz teraz mógł używać mFragments do iteracji przez fragmenty, które obecnie istnieją w FragmentStatePagerAdapter.
źródło
Ta klasa radzi sobie bez polegania na tagach wewnętrznych. Ostrzeżenie: Dostęp do fragmentów należy uzyskiwać za pomocą metody getFragment, a nie metody getItem.
źródło
Po prostu spróbuj tego kodu,
źródło