FragmentManager führt bereits Transaktionen aus. Wann ist es sicher, den Pager nach dem Festschreiben zu initialisieren?

74

Ich habe eine Aktivität, die zwei Fragmente hostet. Die Aktivität zeigt zunächst einen Lader an, während ein Objekt geladen wird. Das geladene Objekt wird dann über newInstance-Methoden als Argumente an beide Fragmente übergeben, und diese Fragmente werden angehängt.

final FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.container1, Fragment1.newInstance(loadedObject));
trans.replace(R.id.container2, Fragment2.newInstance(loadedObject));
trans.commit();

Das zweite Fragment enthält einen android.support.v4.view.ViewPager und Registerkarten. onResume initialisieren wir wie folgt

viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(adapter.getCount()); //the count is always < 4
tabLayout.setupWithViewPager(viewPager);

Das Problem ist Android wirft dann

java.lang.IllegalStateException: FragmentManager führt bereits Transaktionen aus

Mit dieser Stapelverfolgung: (Ich habe android.supportdie Paketnamen nur der Kürze halber herausgenommen)

v4.app.FragmentManagerImpl.execSingleAction (FragmentManager.java:1620) unter v4.app.BackStackRecord.commitNowAllowingStateLoss (BackStackRecord.java:637) unter v4.app.FragmentPagerAdapter.finishUpdate (FragmentPagerAdapter.fin .populate (ViewPager.java:1235) unter v4.view.ViewPager.populate (ViewPager.java:1083) unter v4.view.ViewPager.setOffscreenPageLimit (ViewPager.java:847)

Die Daten zeigen, ob setOffscreenPageLimit(...);entfernt wurde. Gibt es eine andere Möglichkeit, dieses Problem zu vermeiden?

Wann im Lebenszyklus ist die Fragmenttransaktion abgeschlossen, sodass ich warten kann, bis mein Pager eingerichtet ist?

Nick Cardoso
quelle
2
Anscheinend wird der Android ViewPagerein NullPointerExceptionInneres onCreateViewdes Fragments im Pager zu einem IllegalStateException : FragmentManager is already executing transactions... für den Fall, dass jemand vorbeikommt und es wissen muss
Lovis

Antworten:

29

Wenn Sie auf SDK 24 und höher abzielen, können Sie Folgendes verwenden:

FragmentTransaction.commitNow()

anstatt commit()

Wenn Sie auf ältere Versionen abzielen, rufen Sie Folgendes an:

FragmentManager.executePendingTransactions()

nach dem anruf an commit()

Marmor
quelle
20
FragmentManager.executePendingTransactions () verursacht ebenfalls die Ausnahme, da in seinem Code execPendingActions () aufgerufen wird -> sureExecReady (true) -> if (mExecutingActions) {neue IllegalStateException auslösen ("FragmentManager führt bereits Transaktionen aus") ;; }
user2924714
12
Das funktioniert bei mir nicht. Die beiden Methoden zeigen den Absturz: java.lang.IllegalStateException: FragmentManager führt bereits Transaktionen aus
thalissonestrela
commitNow zusammen mit der Verwendung von addToBackStack schlug ebenfalls fehl :(
Narendra Singh
199

Einfach childFragmentManger()für viewpagerinnen a verwendenFragment

mPagerAdapter = new ScreenSlidePagerAdapter(getChildFragmentManager());
mPager.setAdapter(mPagerAdapter);
Hitesh Sahu
quelle
18
Kumpel! Du hast meinen Tag gerettet!! : D Vielen Dank! Ich habe verschachtelte Fragmente verwendet und Ihr Trick "getChildFragmentManager" hat wie ein Zauber funktioniert! ^ _ ^
Vivek Solanki
6
Dies funktionierte in dem Fall, in dem das Zurückkehren (über die Schaltfläche "Zurück") zur Aktivitäts- / Fragment-Kombination ebenfalls abstürzte. Guter Anruf.
Justin
1
Einfache und großartige Lösung. Sie haben mir Zeit gespart. Danke.
Vishva Vijay
Vielen Dank!! Meine App stürzte ab, als ich Änderungen übernehmen und Aktivität neu starten als Ausführungsschaltfläche verwendete.
user1090751
54

Ich hatte diese Ausnahme, als ich schnell 2 Fragmente ersetzte UND executePendingTransactions () verwendete. Ohne dies anzurufen, gab es keine Ausnahme.

Was war mein Fall? Ich öffne ein Fragment A und fordere in seiner onResume () (unter einer Bedingung) die Aktivität auf, das Fragment durch Fragment B zu ersetzen. An diesem Punkt tritt die Ausnahme auf.

Meine Lösung bestand darin, eine Handler.post (ausführbar) zu verwenden, die die Abfrage am Ende der Thread-Warteschlange platziert, anstatt sie sofort auszuführen. Auf diese Weise stellen wir sicher, dass die neue Transaktion ausgeführt wird, nachdem alle vorherigen Transaktionen abgeschlossen wurden.

Meine Lösung war also so einfach wie:

Handler uiHandler = new Handler();
uiHandler.post(new Runnable()
{
    @Override
    public void run()
    {
        openFragmentB(position);
    }
});
M.Paunov
quelle
2
Einfach und effektiv. Ich habe allerdings postDelayed verwendet. In meinem Anwendungsfall war es sogar noch besser, da in der Initialisierungsphase viel los ist
gorodechnyj
1
Das hat funktioniert, aber ich frage mich, wie das Problem intern behoben wird.
David
7

Ich hatte ein ähnliches Problem,

Eine mainAcitivity, die fragmentA hinzufügt.

Dann ruft FragmentA die Hauptaktivität zurück, um sich durch fragment B zu ersetzen.

MainActivity löst die Ausnahme "Fragmentmanager führt Transaktion bereits aus" aus, wenn die Transaktion durch fragmentB ersetzt und festgeschrieben wird.

Das Problem kommt tatsächlich von fragmentB.

Ich habe einen TabHost in Fragment B, für den getfragmentmanager () Tabfragment hinzufügen muss.

Ersetzen Sie getfragmentmanager () durch getchildfragmentmanager () in fragmentB, um das Problem zu beheben.

Alexandre Levieux
quelle
2

Wenn jemand Robolectric> 3.6 und mindestens 4.0.2 mit einem ViewPager verwendet, kann dies auch bei korrektem Code angezeigt werden.

In diesem Github-Problem finden Sie verwandte Informationen , die das Problem für Robolectric verfolgen.

Das Problem ist nicht behoben, während ich diese Antwort schreibe. Die einzigen bekannten Problemumgehungen sind die Verwendung von @Config (sdk = {27}), das für einige zu funktionieren scheint, für mich jedoch nicht funktioniert hat, oder die Implementierung eines ViewPagerShadow mit einer Problemumgehung in Ihrem Testpaket mit dem ziemlich langen Code, auf den auf github verwiesen wird (ich kann ihn hier einfügen, wenn das besser ist, aber dies als Antwort möglicherweise nicht relevant genug ist?) und benutze @Config (shadows = {ShadowViewPager.class})

Mike Hardy
quelle
1

Ich verwendete / erweiterte mein Adapter mit , FragmentStatePagerAdapteranstatt FragmentPagerAdapterdies mein Problem behoben.

Verwenden Sie FragmentStatePagerAdapterdiese Option, wenn die Fragmente dynamisch sind und sich zur Laufzeit häufig ändern.

Verwenden Sie FragmentPagerAdapterdiese Option, wenn die Fragmente statisch sind und sich zur Laufzeit NICHT häufig ändern.

Aus diesem Artikel geht hervor, https://medium.com/inloopx/adventures-with-fragmentstatepageradapter-4f56a643f8e0

Karthik H.
quelle
0

Ich habe einen ähnlichen Fehler, der nicht mit der Frage verbunden ist, aber es hilft jemandem bei der Arbeit mit Firebase. Entfernen Sie die Aktivität, requireActivity oder diese aus .addSnapshotListener () und lassen Sie sie leer.

 videosListener = videosCollectionRef
            .addSnapshotListener() { snapshot, exception ->

                if (exception != null) {
                    Log.e("Exception", "Could not retrieve documents: $exception")
                }

                if (snapshot != null) {
                    parseData(snapshot)
                }
            }
thesamoanppprogrammer
quelle