FragmentManager
to
klasa odpowiedzialna za wykonywanie działań na fragmentach aplikacji, takich jak
ich dodanie, usunięcie lub zastąpienie i dodanie do stosu wstecznego.
Możliwe, że nigdy nie będziesz mieć możliwości bezpośredniej interakcji z usługą FragmentManager
, jeśli jej używasz
z biblioteką Jetpack Navigation, ponieważ współpracuje ona z
FragmentManager
. Każda aplikacja korzystająca z fragmentów jest jednak
używając FragmentManager
, dlatego ważne jest, aby wiedzieć, co
i jak działa.
Tematy na tej stronie:
- Jak uzyskać dostęp do:
FragmentManager
. - Rola
FragmentManager
w odniesieniu do Twoich działań i fragmentów. - Jak zarządzać stosem wstecznym w
FragmentManager
. - Jak dostarczyć dane i zależności do fragmentów.
Dostęp do FragmentManagera
Dostęp do FragmentManager
możesz uzyskać z poziomu aktywności lub z fragmentu.
FragmentActivity
i jego podklas, takich jak
AppCompatActivity
,
dostęp do usługi FragmentManager
za pośrednictwem usługi
getSupportFragmentManager()
.
Fragmenty mogą zawierać jeden lub więcej fragmentów podrzędnych. Wewnątrz
fragment, możesz uzyskać odwołanie do elementu FragmentManager
, którym zarządza
przez elementy podrzędne fragmentu
getChildFragmentManager()
Jeśli musisz uzyskać dostęp do hosta FragmentManager
, możesz użyć
getParentFragmentManager()
Oto kilka przykładów, które pozwolą zobaczyć zależności między
fragmenty, ich hosty i powiązane instancje FragmentManager
z każdą z nich.
Rys. 1 przedstawia dwa przykłady, z których każdy ma jednego hosta aktywności.
aktywność hosta w obu tych przykładach wyświetla nawigację najwyższego poziomu
użytkownika jako
BottomNavigationView
odpowiedzialnym za zamianę fragmentu hosta na inny
w aplikacji. Każdy ekran jest zaimplementowany jako osobny fragment.
Fragment hosta w przykładzie 1 zawiera dwa fragmenty podrzędne, które aby podzielić ekran. Fragment hosta w przykładzie 2 zawiera plik pojedynczy fragment podrzędny, który tworzy wyświetlany fragment widokiem przesuwanym.
Przy takiej konfiguracji każdy host może mieć FragmentManager
który zarządza jego fragmentami podrzędnymi. Zostało to pokazane w
rysunek 2 wraz z mapowaniami właściwości między obiektami supportFragmentManager
,
parentFragmentManager
i childFragmentManager
.
Odpowiednia właściwość FragmentManager
, do której należy się odwołać, zależy od tego, gdzie
witryna wywołania znajduje się w hierarchii fragmentów wraz z menedżerem fragmentów
do której próbujesz uzyskać dostęp.
Jeśli masz odniesienie do elementu FragmentManager
, możesz go użyć do:
i manipulowanie fragmentami wyświetlanymi użytkownikowi.
Fragmenty podrzędne
Ogólnie rzecz biorąc, aplikacja składa się z jednej lub niewielkiej liczby
aktywności w projekcie aplikacji, przy czym każde działanie reprezentuje
grupę powiązanych ekranów. Działanie może być źródłem informacji o tym miejscu.
nawigacja najwyższego poziomu oraz miejsce do zakresu obiektów ViewModel
i innych stanów widoku
między fragmentami. Fragment reprezentuje pojedyncze miejsce docelowe w
.
Aby wyświetlać wiele fragmentów jednocześnie, np. w widoku podzielonym lub panelu, można użyć fragmentów podrzędnych zarządzanych przez fragment docelowy i jego menedżer fragmentów podrzędnych.
Inne przypadki użycia fragmentów podrzędnych:
- Slajdy ekranu,
używanie
ViewPager2
we fragmencie nadrzędnym do zarządzania serią elementów podrzędnych widoki fragmentów. - Nawigacja podrzędna w obrębie zestawu powiązanych ekranów.
- Jetpack Navigation używa fragmentów podrzędnych jako poszczególnych miejsc docelowych. An
aktywność hostuje jeden element nadrzędny
NavHostFragment
i wypełnia jego miejsce z różnymi podrzędnymi fragmentami miejsca docelowego w miarę przechodzenia przez użytkowników do aplikacji.
Korzystanie z narzędzia FragmentManager
Element FragmentManager
zarządza wstecznym stosem fragmentów. W czasie działania
FragmentManager
może wykonywać operacje tworzenia stosu wstecznego, takie jak dodawanie i usuwanie
fragmentów w odpowiedzi na interakcje użytkownika. Każdy zestaw zmian
przedsięwzięcia w formie pojedynczej jednostki zwanej
FragmentTransaction
Więcej informacji o transakcjach fragmentowych znajdziesz w
przewodnika po transakcjach dotyczących fragmentów.
Gdy użytkownik kliknie przycisk Wstecz na swoim urządzeniu lub gdy zadzwonisz
FragmentManager.popBackStack()
transakcja z najwyższym fragmentem ma miejsce w stosie. Jeśli nie ma więcej fragmentów
transakcji na stosie, a jeśli nie używasz fragmentów podrzędnych, fragment Wstecz
dymki powiązane z aktywnością. Jeśli używasz fragmentów podrzędnych, zapoznaj się z artykułem
specjalne uwagi dotyczące fragmentów podrzędnych i równorzędnych.
Gdy dzwonisz
addToBackStack()
w transakcji, transakcja może zawierać dowolną liczbę
operacji, takich jak dodawanie wielu fragmentów lub zastępowanie fragmentów w wielu
kontenery.
Po wysunięciu stosu wstecznego wszystkie te elementy
na odwrót jako pojedyncze, niepodzielne działanie. Jeśli jednak
przed rozmową popBackStack()
, a jeśli
nie użyło addToBackStack()
w przypadku tej transakcji, te operacje
nie odwracaj ich. Dlatego w ramach jednego parametru FragmentTransaction
unikaj
i prowadzimy między nimi.
Wykonaj transakcję
Aby wyświetlić fragment w kontenerze układu, użyj komponentu FragmentManager
aby utworzyć FragmentTransaction
. W ramach transakcji możesz następnie
wykonaj
add()
lub replace()
na kontenerze.
Prosty FragmentTransaction
może na przykład wyglądać tak:
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container) setReorderingAllowed(true) addToBackStack("name") // Name can be null }
Java
FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null) .setReorderingAllowed(true) .addToBackStack("name") // Name can be null .commit();
W tym przykładzie ExampleFragment
zastępuje fragment, który jest
obecnie w kontenerze układu wskazywanego przez
Identyfikator R.id.fragment_container
. Przekazywanie klasy fragmentu do funkcji
replace()
pozwala funkcji FragmentManager
na obsługę instancji za pomocą
FragmentFactory
Więcej informacji znajdziesz w artykule Podawanie zależności fragmentom.
.
setReorderingAllowed(true)
optymalizuje zmiany stanu fragmentów objętych transakcją
by animacje i przejścia działały prawidłowo. Więcej informacji na temat:
nawigowanie z użyciem animacji i przejść, patrz
Transakcje z wykorzystaniem fragmentów
Poruszaj się po fragmentach za pomocą animacji.
Łączę
addToBackStack()
zatwierdza transakcję na stosie wstecznym. Użytkownik może później odwrócić kolejność
transakcji i przywrócić poprzedni fragment, dotykając przycisku Wstecz
Przycisk W przypadku dodania lub usunięcia wielu fragmentów w jednym
wszystkie te operacje są cofane, gdy
zostanie wystrzelony. Opcjonalna nazwa podana w wywołaniu addToBackStack()
daje
możesz wrócić do określonej transakcji za pomocą
popBackStack()
Jeśli nie wywołujesz funkcji addToBackStack()
podczas wykonywania transakcji, która
usuwa fragment, a po jego zniszczeniu – usunięty fragment jest zniszczony.
transakcja jest zatwierdzona i użytkownik nie może wrócić do niej. Jeśli
wywołuje funkcję addToBackStack()
przy usuwaniu fragmentu, wówczas fragment ma postać
tylko STOPPED
i ma wartość RESUMED
, gdy użytkownik wróci. Widok
została zniszczona. Więcej informacji:
Cykl życia fragmentów.
Znajdowanie istniejącego fragmentu
Możesz uzyskać odwołanie do bieżącego fragmentu w kontenerze układu
za pomocą funkcji
findFragmentById()
Użyj funkcji findFragmentById()
, aby wyszukać fragment według podanego identyfikatora, gdy
jest powiększona z pliku XML lub według identyfikatora kontenera, gdy zostanie dodany w funkcji
FragmentTransaction
Oto przykład:
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container) setReorderingAllowed(true) addToBackStack(null) } ... val fragment: ExampleFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as ExampleFragment
Java
FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null) .setReorderingAllowed(true) .addToBackStack(null) .commit(); ... ExampleFragment fragment = (ExampleFragment) fragmentManager.findFragmentById(R.id.fragment_container);
Do fragmentu możesz też przypisać unikalny tag i uzyskać
odwołanie za pomocą
findFragmentByTag()
Możesz przypisać tag, korzystając z atrybutu XML android:tag
we fragmentach, które
są zdefiniowane w układzie lub w parametrze add()
albo replace()
operacji w FragmentTransaction
.
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container, "tag") setReorderingAllowed(true) addToBackStack(null) } ... val fragment: ExampleFragment = supportFragmentManager.findFragmentByTag("tag") as ExampleFragment
Java
FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null, "tag") .setReorderingAllowed(true) .addToBackStack(null) .commit(); ... ExampleFragment fragment = (ExampleFragment) fragmentManager.findFragmentByTag("tag");
Specjalne uwagi dotyczące fragmentów podrzędnych i równorzędnych
Tylko jeden element typu FragmentManager
może kontrolować wsteczny stos fragmentów
w dowolnym momencie. Jeśli aplikacja wyświetla wiele fragmentów równorzędnych w
ekranu w tym samym czasie, a jeśli aplikacja korzysta z fragmentów podrzędnych,
Aplikacja FragmentManager
jest przeznaczona do obsługi głównej nawigacji w aplikacji.
Aby zdefiniować główny fragment nawigacji wewnątrz transakcji opartej na fragmencie,
Wywołaj funkcję
setPrimaryNavigationFragment()
dla transakcji, przekazując wystąpienie fragmentu, którego
Głównym elementem sterującym jest childFragmentManager
.
Omówmy strukturę nawigacji jako serię warstw, z których jako najbardziej zewnętrzną warstwę, pakując od niej każdą warstwę podrzędnych fragmentów. Każda warstwa ma 1 główny fragment nawigacji.
Gdy plecy najbardziej wewnętrzna warstwa kontroluje zachowanie nawigacji. Gdy funkcja w warstwie najbardziej wewnętrznej nie ma więcej transakcji z fragmentami, z których można wrócić, element sterujący wróci do następnej warstwy i będzie się powtarzał do chwili do aktywności.
Jeśli jednocześnie wyświetlane są co najmniej dwa fragmenty, tylko Jeden to główny fragment nawigacji. Ustawianie fragmentu , ponieważ główny fragment nawigacji usuwa oznaczenie z poprzedniego fragment. Na podstawie poprzedniego przykładu, jeśli fragment szczegółów ustawisz jako główny fragment nawigacyjny, oznaczenie fragmentu głównego zostało usunięte.
Obsługa kilku tylnych stosów
W niektórych przypadkach aplikacja może obsługiwać wiele stosów wstecznych. Częstym
Przykład: aplikacja używa dolnego paska nawigacyjnego. FragmentManager
pozwala
obsługujesz kilka tylnych stosów za pomocą funkcji saveBackStack()
i
restoreBackStack()
metod. Te metody umożliwiają przełączanie się między trybami
możesz zapisać jeden stos wsteczny i przywrócić inny.
Funkcja saveBackStack()
działa podobnie do wywoływania popBackStack()
z opcjonalnym
name
: określona transakcja i wszystkie transakcje po niej na
a następnie w wysokiej rozdzielczości. Różnica polega na tym, że saveBackStack()
zapisuje
stan wszystkich fragmentów w wyskakującym okienku
transakcji.
Załóżmy np., że wcześniej do stosu tylnego dodano fragment przez
wymagające FragmentTransaction
za pomocą addToBackStack()
, jak pokazano w
następujący przykład:
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container) setReorderingAllowed(true) addToBackStack("replacement") }
Java
supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null) // setReorderingAllowed(true) and the optional string argument for // addToBackStack() are both required if you want to use saveBackStack() .setReorderingAllowed(true) .addToBackStack("replacement") .commit();
W takim przypadku możesz zapisać transakcję dotyczącą fragmentu oraz stan
ExampleFragment
, dzwoniąc pod numer saveBackStack()
:
Kotlin
supportFragmentManager.saveBackStack("replacement")
Java
supportFragmentManager.saveBackStack("replacement");
Możesz wywołać funkcję restoreBackStack()
z tym samym parametrem name, aby przywrócić wszystkie
wyskakujące transakcje i wszystkie zapisane stany fragmentów:
Kotlin
supportFragmentManager.restoreBackStack("replacement")
Java
supportFragmentManager.restoreBackStack("replacement");
Podaj zależności we fragmentach
Przy dodawaniu fragmentu możesz utworzyć go ręcznie,
Dodaj ją do FragmentTransaction
.
Kotlin
fragmentManager.commit { // Instantiate a new instance before adding val myFragment = ExampleFragment() add(R.id.fragment_view_container, myFragment) setReorderingAllowed(true) }
Java
// Instantiate a new instance before adding ExampleFragment myFragment = new ExampleFragment(); fragmentManager.beginTransaction() .add(R.id.fragment_view_container, myFragment) .setReorderingAllowed(true) .commit();
Gdy zatwierdzisz transakcję dotyczącą fragmentu, wystąpienie fragmentu
jest używana przez Ciebie instancja. Jednak w trakcie
zmianie konfiguracji,
działania i wszystkich jego fragmentów są niszczone, a następnie odtwarzane za pomocą
najbardziej odpowiednia
Materiały dotyczące Androida
FragmentManager
zarządza tym wszystkim za Ciebie: odtwarza wystąpienia
Twoich fragmentów, przyłącza je do hosta i odtwarza tylny stos
stanu.
Domyślnie FragmentManager
używa
FragmentFactory
, które
udostępnia platformę do utworzenia nowego wystąpienia fragmentu. Ten
domyślna fabryka używa refleksji, aby znaleźć i wywołać konstruktor bez argumentu
dla danego fragmentu. Oznacza to, że nie można użyć tej domyślnej opcji fabrycznej, aby
podaj zależności fragmentu. Oznacza to również, że wszystkie niestandardowe
konstruktora użytego do utworzenia fragmentu za pierwszym razem nie jest używany.
podczas odtwarzania.
Aby podać zależności fragmentu lub użyć
konstruktora, zamiast tego utwórz niestandardową podklasę FragmentFactory
.
a następnie zastąp
FragmentFactory.instantiate
Następnie możesz zastąpić domyślną wersję fabryczne urządzenia FragmentManager
za pomocą
niestandardową fabrykę, która jest następnie wykorzystywana do utworzenia wystąpienia fragmentów.
Załóżmy, że w organizacji DessertsFragment
jest odpowiedzialny za wyświetlanie
popularne desery w Twoim mieście, a DessertsFragment
zależność od klasy DessertsRepository
, która udostępnia
informacji, które są niezbędne do wyświetlania użytkownikowi właściwego interfejsu.
Możesz określić, że DessertsFragment
wymaga DessertsRepository
w swoim konstruktorze.
Kotlin
class DessertsFragment(val dessertsRepository: DessertsRepository) : Fragment() { ... }
Java
public class DessertsFragment extends Fragment { private DessertsRepository dessertsRepository; public DessertsFragment(DessertsRepository dessertsRepository) { super(); this.dessertsRepository = dessertsRepository; } // Getter omitted. ... }
Prosta implementacja interfejsu FragmentFactory
może wyglądać podobnie do:
w następujący sposób.
Kotlin
class MyFragmentFactory(val repository: DessertsRepository) : FragmentFactory() { override fun instantiate(classLoader: ClassLoader, className: String): Fragment = when (loadFragmentClass(classLoader, className)) { DessertsFragment::class.java -> DessertsFragment(repository) else -> super.instantiate(classLoader, className) } }
Java
public class MyFragmentFactory extends FragmentFactory { private DessertsRepository repository; public MyFragmentFactory(DessertsRepository repository) { super(); this.repository = repository; } @NonNull @Override public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) { Class<? extends Fragment> fragmentClass = loadFragmentClass(classLoader, className); if (fragmentClass == DessertsFragment.class) { return new DessertsFragment(repository); } else { return super.instantiate(classLoader, className); } } }
Ten przykładowy podklasa FragmentFactory
zastępuje klasę instantiate()
, aby zapewnić niestandardową logikę tworzenia fragmentów dla DessertsFragment
.
Inne klasy fragmentów są obsługiwane przez domyślne zachowanie
FragmentFactory
do super.instantiate()
.
Następnie możesz oznaczyć urządzenie MyFragmentFactory
jako fabryczne, które będzie używane podczas
tworząc fragmenty aplikacji, ustawiając właściwość na
FragmentManager
Musisz ustawić tę właściwość przed
super.onCreate()
, aby mieć pewność, że MyFragmentFactory
jest używany, gdy
na ich odtworzenie.
Kotlin
class MealActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { supportFragmentManager.fragmentFactory = MyFragmentFactory(DessertsRepository.getInstance()) super.onCreate(savedInstanceState) } }
Java
public class MealActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { DessertsRepository repository = DessertsRepository.getInstance(); getSupportFragmentManager().setFragmentFactory(new MyFragmentFactory(repository)); super.onCreate(savedInstanceState); } }
Ustawienie FragmentFactory
w aktywności zastępuje fragment
w całej hierarchii fragmentów aktywności. Innymi słowy,
element childFragmentManager
dowolnego dodanego przez Ciebie fragmentu podrzędnego używa parametru niestandardowego
fabryka fragmentów skonfigurowana tutaj, chyba że zostanie zastąpiona na niższym poziomie.
Testowanie za pomocą FragmentFactory
Przetestuj fragmenty w ramach jednej architektury aktywności
izolacji użytkowników za pomocą
FragmentScenario
zajęcia. Nie można polegać na niestandardowej logice onCreate
w tagu
activity, możesz zamiast tego przekazać FragmentFactory
jako argument
jak w poniższym przykładzie:
// Inside your test val dessertRepository = mock(DessertsRepository::class.java) launchFragment<DessertsFragment>(factory = MyFragmentFactory(dessertRepository)).onFragment { // Test Fragment logic }
Szczegółowe informacje o procesie testowania i pełne przykłady znajdziesz w artykule zapoznaj się z sekcją Testowanie fragmentów.