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

user782104
quelle
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

Ujju
quelle
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");
vovahost
quelle
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 ()

Deep Mehta
quelle
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.

Mihab
quelle
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 ...

Mehul Solanki
quelle
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.

Mist Nguyen
quelle
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();
Farid Haq
quelle
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).

CoolMind
quelle
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.

Seto
quelle
0

Fügen Sie das Fragment wie folgt hinzu

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
    t.replace(R.id.realtabcontent, mFrag);
    t.addToBackStack(null);
    t.commitNowAllowingStateLoss();
M.Noman
quelle
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..
}
Mr. Lemon
quelle