FragmentManager
ist
Die Klasse, die für die Durchführung von Aktionen an den App-Fragmenten verantwortlich ist, z. B.
hinzufügen, entfernen oder ersetzen
und sie dem Back-Stack hinzufügen.
Sie interagieren möglicherweise nie direkt mit FragmentManager
, wenn Sie
Jetpack Navigation-Bibliothek, da sie mit der
FragmentManager
in deinem Namen. Jede Anwendung, die Fragmente verwendet,
FragmentManager
verwenden. Es ist daher wichtig zu verstehen,
wie es ist und wie es funktioniert.
Auf dieser Seite werden folgende Themen behandelt:
- So greifen Sie auf die
FragmentManager
zu. - Die Rolle von
FragmentManager
in Bezug auf deine Aktivitäten und Fragmente. - So verwalten Sie den Back-Stack mit
FragmentManager
. - So stellen Sie Daten und Abhängigkeiten für Ihre Fragmente bereit.
Auf FragmentManager zugreifen
Du kannst über eine Aktivität oder ein Fragment auf das FragmentManager
zugreifen.
FragmentActivity
und ihre abgeleiteten Klassen, z. B.
AppCompatActivity
,
haben über das FragmentManager
getSupportFragmentManager()
.
Fragmente können ein oder mehrere untergeordnete Fragmente hosten. Innenansicht
ein Fragment, können Sie einen Verweis auf das FragmentManager
abrufen, das
die untergeordneten Elemente des Fragments durch
getChildFragmentManager()
Wenn Sie auf den Host FragmentManager
zugreifen müssen, können Sie Folgendes verwenden:
getParentFragmentManager()
Die folgenden Beispiele veranschaulichen die Zusammenhänge zwischen
Fragmente, ihre Hosts und die zugeordneten FragmentManager
-Instanzen
mit jedem Bild.
Abbildung 1 zeigt zwei Beispiele, von denen jedes einen einzelnen Aktivitätshost hat. Die
„Host-Aktivität“ in diesen beiden Beispielen zeigt die Navigation der obersten Ebene zu
Nutzende als
BottomNavigationView
das für den Austausch des Hostfragments
Bildschirmen in der App. Jeder Bildschirm wird als separates Fragment implementiert.
Das Hostfragment in Beispiel 1 hostet zwei untergeordnete Fragmente, Split View erstellen. Das Hostfragment in Beispiel 2 hostet ein einzelnes untergeordnetes Fragment, das das Anzeigefragment eines Ansicht wischen.
Angesichts dieser Konfiguration können Sie sich jeden Host als einen FragmentManager
vorstellen
zur Verwaltung der untergeordneten Fragmente. Dies wird in
Abbildung 2 zusammen mit Property-Zuordnungen zwischen supportFragmentManager
,
parentFragmentManager
und childFragmentManager
.
Auf welches FragmentManager
-Attribut verwiesen werden soll, hängt davon ab,
die Aufrufwebsite befindet sich in der Fragmenthierarchie und in welchem Fragmentmanager
auf die Sie zugreifen möchten.
Sobald du einen Verweis auf FragmentManager
hast, kannst du damit Folgendes tun:
die dem Nutzer angezeigten Fragmente zu manipulieren.
Untergeordnete Fragmente
Im Allgemeinen besteht Ihre App aus einer einzigen oder
der Aktivitäten in Ihrem Anwendungsprojekt, wobei jede Aktivität für
zusammengehörigen Bildschirmen. Die Aktivität könnte einen
Anhaltspunkt dafür liefern,
Navigation der obersten Ebene und ein Ort, an dem Sie ViewModel
-Objekte und andere Ansichtsstatus festlegen können
zwischen den Fragmenten. Ein Fragment stellt ein einzelnes Ziel in Ihrer
Wenn Sie mehrere Fragmente gleichzeitig anzeigen möchten, beispielsweise in einer geteilten Ansicht, oder ein Dashboard, können Sie untergeordnete Fragmente verwenden, die von Ihrem Zielfragment und sein untergeordneter Fragmentmanager.
Weitere Anwendungsfälle für untergeordnete Fragmente:
- Bildschirmfolien,
Verwenden einer
ViewPager2
in einem übergeordneten Fragment, um eine Reihe untergeordneter Elemente zu verwalten Fragment-Ansichten. - Subnavigation innerhalb einer Reihe zusammengehöriger Bildschirme.
- Jetpack Navigation verwendet untergeordnete Fragmente als einzelne Ziele. Eine
wird für die Aktivität ein einzelnes übergeordnetes Element (
NavHostFragment
) gehostet und der entsprechende Bereich wird ausgefüllt. mit unterschiedlichen untergeordneten Zielfragmenten für Ihre App.
FragmentManager verwenden
Der FragmentManager
verwaltet den Back-Stack des Fragments. Während der Laufzeit
FragmentManager
kann Back-Stack-Vorgänge wie das Hinzufügen oder Entfernen ausführen
auf Fragmente reagieren. Jede Gruppe von Änderungen
als eine Einheit, die als
FragmentTransaction
Eine ausführlichere Diskussion über Fragmenttransaktionen finden Sie in der
Transaktionsleitfaden für Fragmente nutzen
Wenn der Nutzer auf seinem Gerät auf die Schaltfläche „Zurück“ tippt oder wenn du anrufst
FragmentManager.popBackStack()
,
hebt sich die oberste Fragmenttransaktion
vom Stack ab. Wenn es kein Fragment mehr gibt
Transaktionen im Stapel. Falls Sie keine untergeordneten Fragmente verwenden,
erscheint als Nächstes in der Aktivität. Wenn Sie untergeordnete Fragmente verwenden, lesen Sie den Abschnitt
Besondere Überlegungen für untergeordnete und gleichgeordnete Fragmente.
Wenn du anrufst
addToBackStack()
für eine Transaktion gilt, kann sie eine beliebige Anzahl von
wie das Hinzufügen mehrerer Fragmente oder das Ersetzen von Fragmenten in mehreren
Container.
Wenn der Back Stack platzt,
Operationen umgekehrt als eine einzelne atomare Aktion. Wenn Sie jedoch
vor dem popBackStack()
-Anruf weitere Transaktionen vorgenommen und
addToBackStack()
nicht für die Transaktion verwendet haben, sind diese Vorgänge
nicht rückgängig machen. Vermeiden Sie daher innerhalb einer einzelnen FragmentTransaction
und verschränkt Transaktionen, die sich auf den Back-Stack auswirken, mit solchen, die dies nicht tun.
Transaktion ausführen
Um ein Fragment innerhalb eines Layoutcontainers anzuzeigen, verwenden Sie die Methode FragmentManager
.
um ein FragmentTransaction
zu erstellen. Innerhalb der Transaktion können Sie
eine
add()
oder replace()
für den Container ausgeführt wird.
Ein einfaches FragmentTransaction
könnte beispielsweise so aussehen:
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();
In diesem Beispiel ersetzt ExampleFragment
das Fragment, sofern vorhanden.
sich derzeit im Layout-Container befindet, der vom
R.id.fragment_container
-ID. Bereitstellung der Klasse des Fragments für die
replace()
die Instanziierung mithilfe der Methode FragmentManager
FragmentFactory
Weitere Informationen finden Sie unter Abhängigkeiten für Fragmente bereitstellen.
.
setReorderingAllowed(true)
optimiert die Statusänderungen der an der Transaktion beteiligten Fragmente
damit Animationen und Übergänge korrekt funktionieren. Weitere Informationen zu
Animationen und Übergänge nutzen,
Transaktionen fragmentieren und
Mithilfe von Animationen zwischen Fragmenten wechseln
Anrufen
addToBackStack()
überträgt die Transaktion im Back-Stack. Der Nutzer kann die
und das vorherige Fragment wiederherstellen, indem Sie auf die Schaltfläche
Schaltfläche. Wenn Sie mehrere Fragmente innerhalb eines
werden alle Vorgänge rückgängig gemacht,
wird geplatzt. Mit dem optionalen Namen, der im addToBackStack()
-Aufruf angegeben wird,
können Sie mit der Funktion
popBackStack()
Wenn Sie addToBackStack()
nicht aufrufen, wenn Sie eine Transaktion ausführen,
entfernt ein Fragment, wird das entfernte Fragment gelöscht,
Für die Transaktion wurde ein Commit durchgeführt und der Nutzer kann nicht zu ihr zurückkehren. Wenn Sie
addToBackStack()
aufrufen, wenn ein Fragment entfernt wird, dann wird das Fragment
nur STOPPED
und später RESUMED
, wenn der Nutzer zurücknavigiert. Ansicht
is gelöscht wurde. Weitere Informationen finden Sie unter
Lebenszyklus des Fragments:
Vorhandenes Fragment suchen
Sie können einen Verweis auf das aktuelle Fragment innerhalb eines Layoutcontainers abrufen
mit
findFragmentById()
Verwenden Sie findFragmentById()
, um ein Fragment entweder über die angegebene ID zu suchen, wenn
aus XML oder mit der Container-ID beim Hinzufügen
FragmentTransaction
. Beispiel:
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);
Alternativ können Sie einem Fragment ein eindeutiges Tag zuweisen und eine
Referenz mithilfe von
findFragmentByTag()
Du kannst einem Fragment mithilfe des XML-Attributs android:tag
ein Tag zuweisen,
werden in Ihrem Layout oder während eines add()
- oder replace()
-Vorgangs
innerhalb einer 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");
Besondere Überlegungen für untergeordnete und gleichgeordnete Fragmente
Der Back-Stack des Fragments kann nur von einer einzigen FragmentManager
gesteuert werden
jederzeit ändern. Wenn in Ihrer App mehrere gleichgeordnete Fragmente
oder wenn deine App untergeordnete Fragmente verwendet,
FragmentManager
ist für die primäre Navigation deiner App vorgesehen.
Um das primäre Navigationsfragment innerhalb einer Fragmenttransaktion zu definieren,
ruf die
setPrimaryNavigationFragment()
-Methode für die Transaktion, wobei die Instanz des Fragments übergeben wird, dessen
childFragmentManager
hat die primäre Kontrolle.
Betrachten Sie die Navigationsstruktur als eine Reihe von Ebenen, mit der Aktivität als äußerster Layer und umschließt jede darunterliegende Ebene mit untergeordneten Fragmenten. Jede Ebene hat ein einzelnes primäres Navigationsfragment.
Wenn der Rücken -Ereignis auftritt, steuert die innerste Ebene das Navigationsverhalten. Sobald die die innerste Schicht keine Fragmenttransaktionen mehr enthält, Die Steuerung kehrt zum nächsten Layer zurück. Dieser Vorgang wiederholt sich, bis Sie um die Aktivität zu erreichen.
Wenn zwei oder mehr Fragmente gleichzeitig angezeigt werden, eines davon ist das primäre Navigationsfragment. Fragment festlegen da das primäre Navigationsfragment die Kennzeichnung aus dem vorherigen Fragment. Wenn Sie wie im vorherigen Beispiel das Detailfragment als das primäres Navigationsfragment entfernt, wird die Bezeichnung des Hauptfragments entfernt.
Unterstützung mehrerer Back Stacks
In einigen Fällen muss Ihre App möglicherweise mehrere Back Stacks unterstützen. Eine gemeinsame
Beispiel: Ihre App
verwendet eine Navigationsleiste am unteren Rand. Mit FragmentManager
lassen
Sie unterstützen mehrere Back Stacks mit saveBackStack()
und
restoreBackStack()
-Methoden. Mit diesen Methoden können Sie zwischen
indem Sie einen Back Stack speichern und einen anderen wiederherstellen.
saveBackStack()
funktioniert ähnlich wie der Aufruf von popBackStack()
mit der optionalen
Parameter name
: die angegebene Transaktion und alle darauffolgenden Transaktionen im
Stacks platzen. Der Unterschied besteht darin, dass saveBackStack()
die
aller Fragmente im Pop-up-
Transaktionen.
Angenommen, Sie haben dem Back Stack zuvor ein Fragment hinzugefügt,
Einen Commit eines FragmentTransaction
mit addToBackStack()
durchführen, wie im
folgendes Beispiel:
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();
In diesem Fall können Sie diese Fragmenttransaktion und den Status
ExampleFragment
durch Aufrufen von saveBackStack()
:
Kotlin
supportFragmentManager.saveBackStack("replacement")
Java
supportFragmentManager.saveBackStack("replacement");
Sie können restoreBackStack()
mit demselben Namensparameter aufrufen, um alle
die per POP heruntergeladenen Transaktionen und alle gespeicherten Fragmentstatus:
Kotlin
supportFragmentManager.restoreBackStack("replacement")
Java
supportFragmentManager.restoreBackStack("replacement");
Abhängigkeiten zu Ihren Fragmenten bereitstellen
Beim Hinzufügen eines Fragments können Sie es manuell instanziieren und
Fügen Sie es dem FragmentTransaction
hinzu.
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();
Wenn Sie einen Commit für die Fragmenttransaktion durchführen, wird die Instanz des Fragments
die Sie erstellt haben, ist die verwendete Instanz. Während eines
Konfigurationsänderung haben,
und all ihre Fragmente werden zerstört und dann mit
die am besten geeignete
Android-Ressourcen
FragmentManager
übernimmt all dies für Sie: erstellt Instanzen neu
Ihrer Fragmente, verbindet sie mit dem Host und erstellt den Back Stack neu
Bundesstaat.
Standardmäßig verwendet der FragmentManager
einen
FragmentFactory
, die
das Framework bietet, um eine neue Instanz Ihres Fragments zu instanziieren. Dieses
Die Standard-Factory verwendet Reflexion, um einen No-Argument-Konstruktor zu finden und aufzurufen
für das Fragment. Das bedeutet, dass Sie diese Standard-Werkseinstellungen nicht verwenden können,
Abhängigkeiten zum Fragment bereitstellen. Es bedeutet auch, dass alle benutzerdefinierten
Konstruktor, mit dem Sie das Fragment erstmalig erstellt haben, wird nicht verwendet.
bei der Neuerstellung standardmäßig aktiviert.
Zur Bereitstellung von Abhängigkeiten für Ihr Fragment oder zur Verwendung eines benutzerdefinierten
-Konstruktor erstellen, erstellen Sie stattdessen eine benutzerdefinierte FragmentFactory
-Unterklasse
und dann
FragmentFactory.instantiate
Anschließend können Sie die standardmäßige Factory von FragmentManager
mit
Ihre benutzerdefinierte Factory, mit der Ihre Fragmente instanziiert werden.
Angenommen, Sie haben ein DessertsFragment
, das für die Darstellung
beliebte Desserts in Ihrer Heimatstadt, und dass DessertsFragment
Abhängigkeit von einer DessertsRepository
-Klasse, die sie
die Informationen benötigt, um
Ihren Nutzern die richtige UI anzuzeigen.
Sie können festlegen, dass für Ihre DessertsFragment
ein DessertsRepository
erforderlich ist.
-Instanz in ihrem Konstruktor befinden.
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. ... }
Eine einfache Implementierung Ihrer FragmentFactory
könnte etwa so aussehen:
Folgendes:
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); } } }
In diesem Beispiel wird FragmentFactory
abgeleitet, wodurch instantiate()
überschrieben wird.
, um eine benutzerdefinierte Logik zur Fragmenterstellung für DessertsFragment
bereitzustellen.
Andere Fragmentklassen werden vom Standardverhalten von
FragmentFactory
bis super.instantiate()
.
Sie können dann MyFragmentFactory
als Werkseinstellung festlegen, die verwendet wird, wenn
App-Fragmente durch Festlegen einer Eigenschaft für die
FragmentManager
. Sie müssen diese Eigenschaft vor dem
super.onCreate()
, damit MyFragmentFactory
verwendet wird, wenn
die Reproduktion der Fragmente.
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); } }
Festlegen von FragmentFactory
im Aktivitätsüberschreibungs-Fragment
in der gesamten Fragmenthierarchie der Aktivität erstellt. Mit anderen Worten:
Für childFragmentManager
aller hinzugefügten untergeordneten Fragmente wird das benutzerdefinierte
Das Fragment kann hier festgelegt werden, es sei denn, es wird auf einer niedrigeren Ebene überschrieben.
Mit FragmentFactory testen
Testen Sie Ihre Fragmente in einer Architektur mit einer einzelnen Aktivität in
Isolierung mithilfe der Methode
FragmentScenario
. Da Sie sich nicht auf die benutzerdefinierte onCreate
-Logik Ihres
Aktivität ausführen, können Sie stattdessen FragmentFactory
als Argument übergeben.
dem Fragmenttest hinzugefügt, wie im folgenden Beispiel gezeigt:
// Inside your test val dessertRepository = mock(DessertsRepository::class.java) launchFragment<DessertsFragment>(factory = MyFragmentFactory(dessertRepository)).onFragment { // Test Fragment logic }
Ausführliche Informationen über diesen Testprozess und vollständige Beispiele Siehe Fragmente testen.