IllegalStateException: Fragment bereits im Tabhost-Fragment hinzugefügt


79
FATAL EXCEPTION: main
Process: com.example.loan, PID: 24169
java.lang.IllegalStateException: Fragment already added: FormFragment{428f10c8 #1 id=0x7f050055 form}
    at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1192)
    at android.support.v4.app.BackStackRecord.popFromBackStack(BackStackRecord.java:722)
    at android.support.v4.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1533)
    at android.support.v4.app.FragmentManagerImpl$2.run(FragmentManager.java:489)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1484)
    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:450)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5068)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
    at dalvik.system.NativeStart.main(Native Method)

Also habe ich eine Android App, die mit dem Tabhost erstellt. Insgesamt gibt es drei Registerkarten. In Tab2 befindet sich eine Schaltfläche zum Ausführen der Fragmenttransaktion in Tab2 (die die Funktion in der Fragmentaktivität aufruft.)

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
        t.replace(R.id.realtabcontent, mFrag);
        t.addToBackStack(null);
        t.commit();

Es gibt eine Ausnahme, wenn ich so laufe:

  1. Innerhalb der Registerkarte 2 drücke ich die Taste, um das Fragment zu ändern
  2. Gehen Sie zu einer anderen Registerkarte (z. B. Registerkarte 1 oder Registerkarte 3).
  3. Drücken Sie die Zurück-Taste
  4. Ausnahme auslösen

Wie kann man das beheben? Danke fürs Helfen



Das bedeutet, dass der Backpress ein neues Fragment hinzufügt. Welche Logik hat der Backstack? Vielen Dank
user782104

Wird mFrag neben tab2 auch zu einer anderen Registerkarte hinzugefügt?
Akhil

Antworten:


149

Dies geschieht, wenn wir zweimal versuchen, dasselbe Fragment oder DialogFragment hinzuzufügen, bevor wir es schließen.

Ruf einfach an

if(mFragment.isAdded())
{
     return; //or return false/true, based on where you are calling from
}

Trotzdem sehe ich keinen Grund, das alte Fragment zu entfernen und dasselbe Fragment erneut hinzuzufügen, da wir die Benutzeroberfläche / Daten aktualisieren können, indem wir einfach Parameter an die Methode innerhalb des Fragments übergeben


5
Dies sollte die akzeptierte Antwort sein. Die akzeptierte Antwort macht keinen Sinn. Erstens sollte es keine Negation von geben isAdded(). Zweitens wird in den Kommentaren vorgeschlagen, dass dieser Code eingeht onCreate(), was ebenfalls unsinnig ist. Diese Codezeile sollte direkt vor der Zeile stehen, in der das Fragment hinzugefügt (oder ersetzt) ​​wird, nicht in onCreate()oder onCreateView(). Es ist zu spät, diesen Code in einer dieser Methoden auszuführen.
AndroidDev

3
if(fragment.isAdded()) fragmentTransaction.show(fragment);
Konstantin Konopko

muss auch auf versteckte Fragmente überprüft werden.
Mahdi Moqadasi

Ich muss ähnliche Fragmente hinzufügen und nur die Attribute im Fragment sind unterschiedlich. Es tritt jedoch weiterhin ein doppelter Fehler auf.
Alston

Ich hatte bereits implementiert, um zu überprüfen, ob das Fragment bereits hinzugefügt wurde, und dann zurückzukehren (der Code zum Hinzufügen des Fragments wird nicht ausgeführt), da meine Anwendung im Play Store live ist und ich immer noch das Absturzfragment habe, das von einigen Geräten nicht hinzugefügt wurde Alle Geräte, die ich versuche, es aus dem Monat herauszufinden, ich kann es nicht überwinden, ich hatte eine Reihe von Lösungen angewendet und den Build im Live-Play-Store aktualisiert, dennoch erhalte ich den Fehler von einigen der Geräte wie Galaxy S20 + 5G, huawei, gibt es weniger Geräte, die das Problem haben, das ich habe, jede Hilfe wäre dankbar, danke
Navin

12

Entfernen Sie das alte Fragment, falls es noch hinzugefügt wird, und fügen Sie dann das neue Fragment hinzu:

FragmentManager fm = getSupportFragmentManager();
Fragment oldFragment = fm.findFragmentByTag("fragment_tag");
if (oldFragment != null) {
    fm.beginTransaction().remove(oldFragment).commit();
}
MyFragment newFragment = new MyFragment();
fm.beginTransaction().add(newFragment , "fragment_tag");

Sollten wir keine Argumente senden, um Änderungen am bereits angezeigten Fragment vorzunehmen? anstatt es zu entfernen und wieder hinzuzufügen
Ujju

Sie können die Argumente nicht festlegen, nachdem das Fragment dem Fragmentmanager hinzugefügt wurde. Aus Dokumenten: "Diese Methode kann nicht aufgerufen werden, wenn das Fragment einem FragmentManager hinzugefügt wird und wenn isStateSaved () true zurückgeben würde." Sie müssen Ihre Fragmentmethoden also direkt aufrufen, wenn Sie die Benutzeroberfläche aktualisieren möchten.
Vovahost

Ja, ich wollte nicht über setzen setArguments, bezog sich auf das Senden von Argumenten als zu aktualisierende Parameter, also hat das Entfernen und Hinzufügen desselben Fragments keinen Sinn, oder?
Ujju

Es hängt davon ab, ob. Wenn Sie viele Dinge neu konfigurieren müssen, ist es möglicherweise einfacher, das Fragment einfach durch ein neues zu ersetzen. Es hängt alles von Ihren Bedürfnissen ab.
Vovahost

1
Ich erhalte weiterhin den Fehler, wenn ich eine Transaktion verwende. Dies ist wahrscheinlich auf das asynchrone Verhalten der Arbeit mit dem Fragmentmanager zurückzuführen.
CoolMind

8

Sie müssen nur eine Bedingung in Ihrem unten genannten Fragment überprüfen:

if(!isAdded())
{
    return;
}

isAdded = Gibt true zurück, wenn das Fragment derzeit zu seiner Aktivität hinzugefügt wird. Entnommen aus dem offiziellen Dokument. Dadurch wird dieses Fragment nicht hinzugefügt, wenn es bereits hinzugefügt wurde

Überprüfen Sie den folgenden Link als Referenz:
http://developer.android.com/reference/android/app/Fragment.html#isAdded ()


danke für deine hilfe, meinst du ich habe das if (! isAdded ()) in oncreateview eingefügt?
user782104

Ja, Sie müssen nur den Code eingeben, den ich oben in meiner Antwort erwähnt habe ... Dies bedeutet, dass Ihr Fragment bereits im Stapel hinzugefügt wurde. Sie müssen es also nicht erneut hinzufügen und es wird einfach zurückgegeben.
Deep Mehta

6
Das macht keinen Sinn. Sie können in onCreateView nicht void zurückgeben. Meinten Sie onCreate? Ich habe es dort versucht und es hat meinem Problem nicht
geholfen

5
Wird das hinzugefügt onCreate?
StuStirling

5
Warum das Negationszeichen? Sollte das Fragment nicht hinzugefügt werden, wenn! IsAdded ()?
Alen Siljak

7

Manchmal kommt es vor, dass im jeweiligen Layout keine richtige ID gefunden wird. Ich war mit diesem Problem konfrontiert. Dann, nach vielen Stunden, stellte ich fest, dass ich die falsche Recyclerview-ID eingestellt hatte. Ich ändere es und funktioniert gut für mich.

Überprüfen Sie also Ihr Fragmentlayout.


2
Danke, für mich war es genauso. Die Ausnahmemeldung könnte nicht irreführender sein.
SqueezyMo

Nach mehr als einem Monat für die Untersuchung der Grundursache war dies der Grund. Vielen Dank
Omid Heshmatinia

7

Sie müssen nur eine Bedingung überprüfen, bevor Sie die Fragmenttransaktion starten

 if (!fragmentOne.isAdded()){
            transaction = manager.beginTransaction();
            transaction.add(R.id.group,fragmentOne,"Fragment_One");
            transaction.commit();
 }

das funktioniert perfekt für mich ...


1

Ich habe diesen Fehler, wenn ich mein Body-XML nicht in eine ViewGroup in FrameLayout einbinde.

Error:

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".screens.home.HomeEpoxyFragment">

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swipe_refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv"
            android:overScrollMode="never"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</FrameLayout>

Gelöst:

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".screens.home.HomeEpoxyFragment">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv"
                android:overScrollMode="never"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>

</FrameLayout>

Hoffe das kann jemandem helfen.


0

Für mich funktioniert es wie:

Fragment oldFragment = manager.findFragmentByTag(READER_VIEW_POPUP);
if (oldFragment != null) {
    manager.beginTransaction().remove(oldFragment).commit();
}

FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();

0

Es kann sogar vorkommen, dass Sie in FragmentStatePagerAdapterIhrem ViewPagereinen Artikel erstellen, der bereits vorhanden ist:

override fun getItem(position: Int): Fragment {
    return tabs[0] // Right variant: tabs[position]
}

( private val tabs: List<Fragment>ist eine Liste von Fragmenten in Registerkarten).


Wie haben Sie das gelöst? Es ist meinem Anwendungsfall sehr ähnlich
Mitch

@Mitch, ich schrieb return tabs[position]in der zweiten Zeile.
CoolMind

Ich benutze auch das gleiche Konzept wie, return tabs[position]aber es wirft immer noch einen Fehler
Mitch

@Mitch, sorry, ich weiß nicht ohne Code. Für den allgemeinen Fall verwende ich derzeit stackoverflow.com/a/57161814/2914140 . Glaubst du, FragmentStatePagerAdapterwirft den Fehler ein getItem?
CoolMind

Es ist sehr wahrscheinlich, dass dies die Fehlerquelle ist, da hier die Instanz (en) der von den angezeigten Fragmente ViewPagerabgerufen werden
Mitch,

0

Zu meiner Überraschung habe ich einen dummen Fehler gemacht, indem ich die Fragmenttransaktion zweimal aufgerufen habe:

if (!FirebaseManager.isClientA && !FirebaseManager.isClientB) {
      fragment = new FragmentA();
      getFragmentManager().beginTransaction().add(R.id.fragment_frame, fragment, null).addToBackStack("").commit();
} else if (FirebaseManager.isClientB) {
      fragment = new FragmentB();
} else {
      fragment = new FragmentC();
}
getFragmentManager().beginTransaction().add(R.id.fragment_frame, fragment, null).addToBackStack("").commit();

Stellen Sie sicher, dass Sie nicht den gleichen Fehler machen.


0

Fügen Sie das Fragment wie folgt hinzu

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
    t.replace(R.id.realtabcontent, mFrag);
    t.addToBackStack(null);
    t.commitNowAllowingStateLoss();

Was wird mit alten und neuen Fragmenten passieren? Wird es das Alte durch das Neue ersetzen?
CoolMind

Nein, es wird nicht ersetzt, sondern das vorherige Fragment wird zum Backstack hinzugefügt.
M.Noman

Ich frage mich, ist es möglich? Gestern habe ich ähnlichen Code ausprobiert und eine Fehlermeldung erhalten, siehe stackoverflow.com/questions/38566628/… , da dies zusammen addToBackStacknicht zulässig ist commitNow.
CoolMind

In diesem Link deaktiviert er den Backstack manuell. Mit addToBackStack wird es möglich sein, den hinteren Stapel des Fragments zu verwalten
M.Noman

0

Sie können dies versuchen:

 if (dialogFolderGallery.isAdded()) {
                dialogFolderGallery.dismiss();
            } else { //bla...bla..
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.