Ich habe ein massives Problem mit der Funktionsweise des Android-Fragment-Backstacks und wäre für jede angebotene Hilfe sehr dankbar.
Stellen Sie sich vor, Sie haben 3 Fragmente
[1] [2] [3]
Ich möchte, dass der Benutzer [1] > [2] > [3]
auf dem Rückweg navigieren kann (Drücken der Zurück-Taste) [3] > [1]
.
Wie ich mir vorgestellt hätte, würde dies dadurch erreicht, dass addToBackStack(..)
beim Erstellen der Transaktion, die das Fragment [2]
in den in XML definierten Fragmenthalter bringt, nicht aufgerufen wird.
Die Realität sieht so aus, als ob ich die Transaktion, die ein Fragment anzeigt , nicht aufrufen darf , wenn ich nicht [2]
wieder erscheinen möchte , wenn der Benutzer die Zurück-Taste drückt . Dies scheint völlig kontraintuitiv zu sein (möglicherweise aus der iOS-Welt).[3]
addToBackStack
[3]
Wie auch immer, wenn ich es so mache, wenn ich von [1] > [2]
zurück gehe und zurückdrücke, komme ich [1]
wie erwartet zurück.
Wenn ich gehe [1] > [2] > [3]
und dann zurück drücke, springe ich zurück zu [1]
(wie erwartet). Jetzt passiert das seltsame Verhalten, wenn ich versuche, noch [2]
einmal von zu springen [1]
. Zunächst [3]
wird kurz angezeigt, bevor es [2]
sichtbar wird. Wenn ich an dieser Stelle zurückdrücke, [3]
wird angezeigt, und wenn ich erneut zurückdrücke, wird die App beendet.
Kann mir jemand helfen zu verstehen, was hier los ist?
Und hier ist die Layout-XML-Datei für meine Hauptaktivität:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<fragment
android:id="@+id/headerFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
class="com.fragment_test.FragmentControls" >
<!-- Preview: layout=@layout/details -->
</fragment>
<FrameLayout
android:id="@+id/detailFragment"
android:layout_width="match_parent"
android:layout_height="fill_parent"
/>
Update Dies ist der Code, den ich zum Erstellen durch nav heirarchy verwende
Fragment frag;
FragmentTransaction transaction;
//Create The first fragment [1], add it to the view, BUT Dont add the transaction to the backstack
frag = new Fragment1();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.commit();
//Create the second [2] fragment, add it to the view and add the transaction that replaces the first fragment to the backstack
frag = new Fragment2();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.addToBackStack(null);
transaction.commit();
//Create third fragment, Dont add this transaction to the backstack, because we dont want to go back to [2]
frag = new Fragment3();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.commit();
//END OF SETUP CODE-------------------------
//NOW:
//Press back once and then issue the following code:
frag = new Fragment2();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.addToBackStack(null);
transaction.commit();
//Now press back again and you end up at fragment [3] not [1]
Danke vielmals
quelle
Antworten:
Erklärung: Was ist hier los?
Wenn wir bedenken, dass dies dem
.replace()
entspricht.remove().add()
, was wir aus der Dokumentation wissen:dann ist das, was passiert, so (ich füge dem Frag Zahlen hinzu, um es klarer zu machen):
(hier beginnt alles irreführende Zeug zu passieren)
Denken Sie daran, dass
.addToBackStack()
nur die Transaktion gespeichert wird, nicht das Fragment als solches! Nun haben wir alsofrag3
das Layout:Mögliche Lösung
Erwägen Sie die Implementierung
FragmentManager.BackStackChangedListener
, um nach Änderungen im Backstack zu suchen und Ihre Logik in deronBackStackChanged()
Methode anzuwenden :FragmentTransaction.addToBackStack(String name);
quelle
FragmentManager.BackStackChangedListener
, um nach Änderungen am Backstack zu suchen . Überwachen Sie alle Ihre Transaktionen mitonBackStackChanged()
Methode und handeln Sie nach Bedarf: zum Beispiel. Verfolgen Sie die Anzahl der Transaktionen in BackStack. Überprüfen Sie bestimmte Transaktion durch Name (FragmentTransaction addToBackStack (String name)
) usw.Richtig!!! Nach langem Ziehen der Haare habe ich endlich herausgefunden, wie man das richtig macht.
Es scheint, als würde Fragment [3] nicht aus der Ansicht entfernt, wenn der Rücken gedrückt wird. Sie müssen dies also manuell tun!
Verwenden Sie zunächst nicht replace (), sondern entfernen und fügen Sie separat hinzu. Es scheint, als ob replace () nicht richtig funktioniert.
Der nächste Teil dazu ist das Überschreiben der onKeyDown-Methode und das Entfernen des aktuellen Fragments bei jedem Drücken der Zurück-Taste.
Hoffe das hilft!
quelle
Zunächst einmal danke @Arvis für eine Erklärung, die die Augen öffnet.
Ich bevorzuge eine andere Lösung als die hier akzeptierte Antwort für dieses Problem. Ich mag es nicht mehr als unbedingt notwendig, mit dem Überschreiben des Back-Verhaltens herumzuspielen, und als ich versucht habe, Fragmente selbst hinzuzufügen und zu entfernen, ohne dass der Standard-Back-Stack beim Drücken der Back-Taste platzt, habe ich mich in der Fragment-Hölle wiedergefunden :) Wenn Sie. Wenn Sie f2 über f1 hinzufügen, wenn Sie es entfernen, ruft f1 keine der Rückrufmethoden wie onResume, onStart usw. auf, und das kann sehr unglücklich sein.
Jedenfalls mache ich das so:
Derzeit ist nur das Fragment f1 zu sehen.
f1 -> f2
nichts Außergewöhnliches hier. Als in Fragment f2 führt Sie dieser Code zu Fragment f3.
f2 -> f3
Ich bin mir nicht sicher, ob diese Poping-Transaktionsmethode beim Lesen von Dokumenten asynchron sein soll. Ein besserer Weg wäre vielleicht, popBackStackImmediate () aufzurufen. Aber soweit ich auf meinen Geräten feststellen kann, funktioniert es einwandfrei.
Die besagte Alternative wäre:
Hier wird es tatsächlich einen kurzen Rückblick auf f1 geben, bevor auf f3 übergegangen wird, also ein kleiner Fehler dort.
Dies ist eigentlich alles, was Sie tun müssen, ohne das Verhalten des Backstacks überschreiben zu müssen ...
quelle
Ich weiß, dass es eine alte Frage ist, aber ich habe das gleiche Problem und behebe es wie folgt:
Fügen Sie zunächst Fragment1 mit einem Namen (z. B. "Frag1") zu BackStack hinzu:
Wenn Sie dann zu Fragment1 zurückkehren möchten (auch nachdem Sie 10 Fragmente darüber hinzugefügt haben), rufen Sie einfach popBackStackImmediate mit dem Namen auf:
Hoffe es wird jemandem helfen :)
quelle
Nach der Antwort von @Arvis habe ich mich entschlossen, noch tiefer zu graben, und ich habe hier einen technischen Artikel darüber geschrieben: http://www.andreabaccega.com/blog/2015/08/16/how-to-avoid-fragments-overlapping- wegen-Backstack-Albtraum-in-Android /
Für die faulen Entwickler. Meine Lösung besteht darin, die Transaktionen immer zum Backstack hinzuzufügen und
FragmentManager.popBackStackImmediate()
bei Bedarf (automatisch) eine zusätzliche Transaktion durchzuführen .Der Code besteht aus sehr wenigen Codezeilen, und in meinem Beispiel wollte ich von C nach A springen, ohne zu "B" zurückzuspringen, wenn der Benutzer nicht tiefer in den Backstack gegangen ist (z. B. von C nach D).
Daher würde der angehängte Code wie folgt funktionieren: A -> B -> C (zurück) -> A & A -> B -> C -> D (zurück) -> C (zurück) -> B (zurück) -> A.
wo
wurden wie in der Frage von "B" nach "C" ausgegeben.
Ok, ok hier ist der Code :)
quelle
Wenn Sie mit addToBackStack () & popBackStack () zu kämpfen haben, verwenden Sie einfach
Finden Sie in Ihrer Aktivität in OnBackPressed () die Farcement nach Tag heraus und erledigen Sie dann Ihre Aufgaben
Weitere Informationen https://github.com/DattaHujare/NavigationDrawer Ich verwende addToBackStack () niemals zur Behandlung von Fragmenten.
quelle
Ich denke, wenn ich Ihre Geschichte lese, ist [3] auch im Hintergrund. Dies erklärt, warum es aufleuchtet.
Die Lösung wäre, niemals [3] auf den Stapel zu setzen.
quelle
s old method issue but now it
Ordnung. DankeIch hatte ein ähnliches Problem, bei dem ich 3 aufeinanderfolgende Fragmente in demselben
Activity
[M1.F0] -> [M1.F1] -> [M1.F2] hatte, gefolgt von einem Aufruf eines neuenActivity
[M2]. Wenn der Benutzer eine Taste in [M2] drückte, wollte ich zu [M1, F1] anstelle von [M1, F2] zurückkehren, was das Verhalten beim Zurückdrücken bereits tat.Um dies zu erreichen, entferne ich [M1, F2], rufe show auf [M1, F1] auf, schreibe die Transaktion fest und füge dann [M1, F2] zurück, indem ich sie mit hide aufrufe. Dadurch wurde die zusätzliche Rückpresse entfernt, die sonst zurückgeblieben wäre.
Hallo, nachdem ich diesen Code ausgeführt habe: Ich kann den Wert von Fragment2 beim Drücken der Zurück-Taste nicht sehen. Mein Code:
quelle
executePendingTransactions()
,commitNow()
nicht funktioniert (Arbeitete in Androidx (Jetpack).
quelle