IllegalStateException: Fragmento ya agregado en el fragmento de tabhost

81
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)

Entonces, tengo una aplicación de Android que se construye con tabhost. Hay tres pestañas en total, en la pestaña2, hay un botón para realizar la transacción del fragmento en la pestaña2 (que está llamando a la función en la actividad del fragmento)

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

Hay una excepción si corro así:

  1. Dentro de la pestaña 2, presiono el botón para cambiar el fragmento
  2. Ir a otra pestaña (por ejemplo, pestaña 1 o pestaña 3)
  3. Presione el botón de retroceso
  4. Lanzar excepción

¿Cómo arreglar eso? Gracias por ayudar

usuario782104
fuente
eso significa que el backpress está agregando un nuevo fragmento, ¿cuál es la lógica en el backstack? Muchas gracias
user782104
¿Se agrega mFrag a alguna otra pestaña además de tab2?
Akhil

Respuestas:

152

Esto sucede cuando intentamos agregar el mismo fragmento o DialogFragment dos veces antes de descartar,

solo llama

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

Habiendo dicho eso, no veo ninguna razón por la que eliminar el fragmento antiguo y agregar el mismo fragmento nuevamente, ya que podemos actualizar la interfaz de usuario / datos simplemente pasando parámetros al método dentro del fragmento

Ujju
fuente
5
Esta debería ser la respuesta aceptada. La respuesta aceptada no tiene sentido. Primero, no debería haber negación de isAdded(). En segundo lugar, en los comentarios, se sugiere que este código se incluya onCreate(), lo que también es absurdo. Esta línea de código debe colocarse directamente antes de la línea donde se agrega (o reemplaza) el fragmento, no en onCreate()o onCreateView(). Es demasiado tarde para ejecutar ese código en cualquiera de esos métodos.
AndroidDev
3
if(fragment.isAdded()) fragmentTransaction.show(fragment);
Konstantin Konopko
También debe comprobarse si hay fragmentos ocultos.
Mahdi Moqadasi
Necesito agregar fragmentos similares y solo los atributos en el fragmento son diferentes. Pero todavía se produce un error duplicado.
Alston
Ya había implementado para verificar si el fragmento ya se agregó y luego regresar (el código de agregar fragmento no se ejecutará), ya que mi aplicación está en vivo en la tienda de juegos, todavía tengo el fragmento de falla ya agregado desde algunos de los dispositivos que no todos los dispositivos que estoy tratando de resolver desde el mes pasado, no puedo superarlo, apliqué una cantidad de soluciones y actualicé la compilación en la tienda de juegos en vivo, todavía estoy recibiendo el error de algunos de los dispositivos como Galaxy S20 + 5G, huawei, hay menos dispositivos que tienen el problema que tengo, cualquier ayuda sería apreciada gracias
Navin
12

Elimine el fragmento antiguo en caso de que aún se agregue y luego agregue el nuevo fragmento:

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
fuente
¿No deberíamos enviar argumentos para realizar cambios en el fragmento ya mostrado? en lugar de eliminarlo y agregarlo nuevamente
Ujju
No puede establecer los argumentos después de que el fragmento se agregó al administrador de fragmentos. De los documentos: "No se puede llamar a este método si el fragmento se agrega a un FragmentManager y si isStateSaved () devolvería verdadero". Por lo tanto, debe llamar a sus métodos de fragmento directamente si desea actualizar la interfaz de usuario.
vovahost
sí, no me refiero a configurar via setArguments, me refería a enviar argumentos como parámetros para actualizar, por lo que eliminar y agregar el mismo fragmento no tiene ningún uso, ¿verdad?
Ujju
Depende. Si necesita reconfigurar muchas cosas, puede ser más fácil simplemente reemplazar el fragmento por uno nuevo. Todo depende de tus necesidades.
vovahost
1
Sigo recibiendo el error, si uso una transacción. Probablemente esto se deba al comportamiento asincrónico del trabajo con el administrador de fragmentos.
CoolMind
8

Solo tiene que verificar una condición en su fragmento que se menciona a continuación:

if(!isAdded())
{
    return;
}

isAdded = Devuelve verdadero si el fragmento se agrega actualmente a su actividad. Tomado del documento oficial. Esto no agregará ese fragmento si ya está agregado

Consulte el siguiente enlace para obtener una referencia:
http://developer.android.com/reference/android/app/Fragment.html#isAdded ()

Deep Mehta
fuente
gracias por su ayuda, ¿quiere decir que puse el if (! isAdded ()) dentro de oncreateview?
user782104
Sí, solo tiene que poner ese código que mencioné en mi respuesta anterior ... Significa que su fragmento ya está agregado en la pila. Entonces, no es necesario agregarlo nuevamente y regresa simplemente.
Deep Mehta
6
esto no tiene sentido, no puede devolver vacío en onCreateView, ¿quiso decir onCreate? Probé esto allí y no ayudó con mi problema
Fonix
5
¿Esto se agrega a onCreate?
StuStirling
5
¿Por qué el signo de la negación? ¿No debería añadirse el fragmento si! IsAdded ()?
Alen Siljak
7

A veces sucede por no encontrar la identificación adecuada en el diseño respectivo. Me enfrenté a este problema. Luego, después de muchas horas, descubrí que configuré una identificación de reciclaje incorrecta. Lo cambio y funciona bien para mí.

Entonces, revise el diseño de su fragmento.

Mihab
fuente
2
Gracias, a mí me pasó lo mismo. El mensaje de excepción no podría ser más engañoso.
SqueezyMo
Después de más de un mes para investigar la causa raíz, esta fue la razón. Muchas gracias
Omid Heshmatinia
7

Solo tiene que verificar una condición antes de comenzar la transacción del fragmento

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

esto está funcionando perfectamente para mí ...

Mehul Solanki
fuente
1

Tengo este error cuando no envuelvo el XML de mi cuerpo dentro de un ViewGroup dentro de FrameLayout.

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>

Resuelto:

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

Espero que esto pueda ayudar a alguien.

Dung Nguyen
fuente
0

Para mi funciona como:

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
fuente
0

Incluso puede ocurrir si en FragmentStatePagerAdaptertu ViewPagercreas un artículo que ya existe:

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

( private val tabs: List<Fragment>es una lista de fragmentos en pestañas).

CoolMind
fuente
Como solucionaste esto? Es muy similar a mi caso de uso
Mitch
@Mitch, escribí return tabs[position]en la segunda línea.
CoolMind
También estoy usando el mismo concepto que, return tabs[position]pero todavía arroja un error
Mitch
@Mitch, lo siento, no lo sé sin un código. Para el caso general, actualmente uso stackoverflow.com/a/57161814/2914140 . ¿Crees que FragmentStatePagerAdapterarroja el error getItem?
CoolMind
Es muy probable que sea la fuente del error, ya que es donde ViewPagerse recuperan las instancias de los fragmentos mostrados por el
Mitch
0

Para mi sorpresa, cometí un error estúpido al llamar dos veces a la transacción del fragmento:

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();

Asegúrese de no cometer el mismo error.

Seto
fuente
0

Agregar fragmento como se muestra a continuación

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
    t.replace(R.id.realtabcontent, mFrag);
    t.addToBackStack(null);
    t.commitNowAllowingStateLoss();
M.Noman
fuente
¿Qué pasará con los fragmentos nuevos y viejos? ¿Reemplazará lo viejo por lo nuevo?
CoolMind
No, no lo reemplazará, agregará el fragmento anterior a la pila de actividades.
M.Noman
Me pregunto si es posible Ayer probé un código similar y obtuve un error, consulte stackoverflow.com/questions/38566628/… , porque addToBackStackno está permitido junto con commitNow.
CoolMind
En ese enlace, está deshabilitando manualmente la pila de actividades. Con addToBackStack, permitirá administrar la pila posterior del fragmento
M.Noman
0

Puedes probar esto:

 if (dialogFolderGallery.isAdded()) {
                dialogFolderGallery.dismiss();
            } else { //bla...bla..
}
Señor limón
fuente
0

Recibí este error cuando usé incorrectamente mi ViewModel dentro de Fragment como este:

//This is wrong!
MyViewModel viewModel = new MyViewModel(getActivity().getApplication());

Manera correcta:

viewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication())).get(MyViewModel.class);
Kamil R.
fuente
0

Aquí mi solución para Fragmento de diálogo (puede usar este concepto también para la clase de fragmento)

He intentado hacer clic en mostrar fragmento de diálogo pulsando el botón varias veces y rápidamente.

            FragmentManager fm = getSupportFragmentManager();
            Fragment oldFragment = fm.findFragmentByTag("wait_modal");

            if(oldFragment != null && oldFragment.isAdded())
                return;

            if(oldFragment == null && !please_wait_modal.isAdded() && !please_wait_modal.isVisible()){
                fm.executePendingTransactions();
                please_wait_modal.show(fm,"wait_modal");
            }
IA de Yohanes
fuente