Limpiar la pila usando fragmentos


244

Porté mi aplicación de Android a Honeycomb e hice una gran refactorización para usar fragmentos. En mi versión anterior, cuando presioné el botón de Inicio, solía hacer un ACTIVITY_CLEAR_TOPpara restablecer la pila de respaldo.

Ahora mi aplicación es solo una Actividad con múltiples fragmentos, así que cuando presiono el botón de Inicio, simplemente reemplazo uno de los fragmentos que contiene. ¿Cómo puedo limpiar mi back stack sin tener que usarlo startActivitycon la ACTIVITY_CLEAR_TOPbandera?


¡Evita usar pilas traseras! ¡realmente no ayuda con la eficiencia general! ¡use replace () o incluso elimine / agregue cada vez que quiera navegar! Consulte mi publicación en stackoverflow.com/questions/5802141/…
stack_ved

Respuestas:


430

Publiqué algo similar aquí

De la respuesta de Joachim, de Dianne Hackborn:

http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42

Terminé simplemente usando:

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {    
    fm.popBackStack();
}

Pero igualmente podría haber usado algo como:

((AppCompatActivity)getContext()).getSupportFragmentManager().popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

Lo que mostrará todos los estados hasta el nombre. Luego puedes reemplazar el fragmento con lo que quieras


8
Bueno, es equivalente a presionar el botón Atrás una o más veces, por lo que cambia el fragmento que está visible actualmente. (Al menos cuando lo he intentado)
Peter Ajtai

77
Estoy teniendo el mismo problema que Peter. Me gustaría eliminar todos los fragmentos en lugar de hacer que los recorra en ciclo, lo que tiene muchas implicaciones. Por ejemplo, llegará a los eventos del ciclo de vida que no necesita haciendo estallar cada fragmento de la pila secuencialmente.
Brian Griffey

233
Para ir al principio, simplemente use: fragmentManager.popBackStack (nulo, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Warpzit

53
Por lo que vale, usando fragmentManager. popBackStackImmediate (nulo, FragmentManager.POP_BACK_STACK_INCLUSIVE); trabajado aún mejor para mí, ya que impidió que las animaciones de los fragmentos de la ejecución
roarster

17
Esto NO funciona correctamente: activará una llamada al inicio de cada fragmento intermedio
James

165

Para responder al comentario de @ Warpzit y facilitar que otros lo encuentren.

Utilizar:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

14
Creo que extraer todos los fragmentos de la pila de esta manera se ha roto en la última biblioteca v7-appCompat cuando se usa AppCompatActivity. Después de actualizar mi aplicación a la última biblioteca v7-appCompat (21.0.0) y extender la nueva AppCompatActivity, hacer estallar fragmentos de la manera anterior deja algunos fragmentos en el registro de backstack del FragmentManager. Aconsejaría no usar esto.
dell116

Se puede usar popBackStackImmediate.
Kannan_SJD

38

Con el debido respeto a todas las partes involucradas; Estoy muy sorprendido de ver cuántos de ustedes podrían limpiar todo el back stack del fragmento con un simple

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

De acuerdo con la documentación de Android (con respecto al nameargumento, el "nulo" en las propuestas de trabajo reclamadas).

Si es nulo, solo aparece el estado superior

Ahora, me doy cuenta de que no tengo conocimiento de sus implementaciones particulares (como cuántas entradas tiene en la pila posterior en el momento dado), pero apostaría todo mi dinero en la respuesta aceptada cuando espero una respuesta bien definida comportamiento en una gama más amplia de dispositivos y proveedores:

(para referencia, algo junto con esto)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}

44
para mí no fue así, ya que cada pop te lleva internamente al onCreateView de cada fragmento. Donde recibiría un NPE en algún recurso. Pero usando fm.popBackStack (nulo, FragmentManager.POP_BACK_STACK_INCLUSIVE); simplemente mató a todo el backstack.
sud007

1
¿Alguna idea sobre cómo omitir las llamadas onCreateView cuando aparece usando loop?
Ayush Goyal

Al borrar el fragmento más alto (nulo) se borrarán todos los fragmentos que vienen después en la pila posterior.
2b77bee6-5445-4c77-b1eb-4df3e5

18

Funciona para mí y de manera fácil sin usar loop:

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

17

La respuesta aceptada no fue suficiente para mí. Tuve que usar:

FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
    fm.popBackStackImmediate();
}

2
Esto se señaló en una respuesta diferente, pero solo para asegurarse de que se tenga en cuenta: si coloca toda la pila en un bucle como este, activará los métodos de ciclo de vida para cada Fragmento entre el inicio y el final de la pila . Existe una buena posibilidad de que esta implementación tenga consecuencias no deseadas, en la mayoría de los casos de uso. También vale la pena señalar que popBackStackImmediate()realiza la transacción sincrónicamente, lo cual, en general, es desaconsejable.
Damien Diehl el

16

Backstack claro sin bucles

String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Donde nombre es el parámetro addToBackStack ()

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)

incluso si reemplazas .fragment stack estará vivo pero no visible
Asthme

8

Solo quería agregar: -

Saliendo del backstack usando los siguientes

fragmentManager.popBackStack ()

se trata solo de eliminar los fragmentos de la transacción, de ninguna manera va a eliminar el fragmento de la pantalla. Entonces, idealmente, puede que no sea visible para usted, pero puede haber dos o tres fragmentos apilados uno sobre el otro, y al presionar la tecla de retroceso, la IU puede verse desordenada, apilada.

Solo tomando un ejemplo simple: -

Supongamos que tiene un fragmento A que carga Fragmnet B usando fragmentmanager.replace () y luego agregamos AddToBackStack, para guardar esta transacción. Entonces el flujo es: -

PASO 1 -> Fragmento A-> Fragmento B (nos mudamos a Fragmento B, pero el Fragmento A está en segundo plano, no visible).

Ahora realiza un trabajo en el fragmento B y presiona el botón Guardar, que después de guardar debe volver al fragmento A.

PASO 2-> Al guardar FragmentB, volvemos a FragmentA.

PASO 3 -> Entonces, un error común sería ... en el Fragmento B, haremos el fragmento Manager.replace () fragmentB con fragmentA.

Pero lo que realmente está sucediendo es que estamos cargando el Fragmento A nuevamente, reemplazando el Fragmento B. Entonces ahora hay dos FragmentA (uno de STEP-1, y uno de este STEP-3).

Dos instancias de FragmentsA están apiladas una sobre otra, lo que puede no ser visible, pero está ahí.

Entonces, incluso si limpiamos el backstack mediante los métodos anteriores, la transacción se borra pero no los fragmentos reales. Entonces, idealmente en un caso tan particular, al presionar el botón Guardar simplemente necesita volver al fragmento A simplemente haciendo fm.popBackStack () o fm.popBackImmediate () .

Entonces, el Paso 3-> fm.popBackStack () correcto vuelve al fragmento A, que ya está en la memoria.


3

Al leer la documentación y estudiar cuál es la identificación del fragmento, parece ser simplemente el índice de la pila, por lo que esto funciona:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Cero ( 0) es la parte inferior de la pila, por lo que al abrirla se borra la pila.

CAVEAT: Aunque lo anterior funciona en mi programa, dudo un poco porque la documentación de FragmentManager nunca indica que la identificación es el índice de la pila. Tiene sentido que lo sea, y todos mis registros de depuración revelan que lo es, pero tal vez en alguna circunstancia especial no lo haría. ¿Puede alguien confirmar esto de una forma u otra? Si es así, entonces lo anterior es la mejor solución. Si no, esta es la alternativa:

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }

1
¿Qué tal usar en fragmentManager..getBackStackEntryAt(0).getId()lugar de 0? Esto debería funcionar incluso si los identificadores de entrada de backstack son en algún punto diferentes del índice de pila.
ChristophK

3

Simplemente use este método y pase la etiqueta Context & Fragment a la que necesitamos eliminar los fragmentos backstake.

Uso

clearFragmentByTag(context, FragmentName.class.getName());



public static void clearFragmentByTag(Context context, String tag) {
    try {
        FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();

        for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
            String backEntry = fm.getBackStackEntryAt(i).getName();
            if (backEntry.equals(tag)) {
                break;
            } else {
                 fm.popBackStack();
            }
        }
    } catch (Exception e) {
        System.out.print("!====Popbackstack error : " + e);
        e.printStackTrace();
    }
}

2

Hola ~ Encontré una solución que es mucho mejor, desde: https://gist.github.com/ikew0ng/8297033

    /**
 * Remove all entries from the backStack of this fragmentManager.
 *
 * @param fragmentManager the fragmentManager to clear.
 */
private void clearBackStack(FragmentManager fragmentManager) {
    if (fragmentManager.getBackStackEntryCount() > 0) {
        FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
        fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }
}

2
Expanda su respuesta con por qué esta solución es mejor.
Simon.SA

Utiliza el mecanismo que proporciona el SDK, y no causará ningún problema npe.
Chenxi

1

Tengo esto trabajando de esta manera:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}

1

Está funcionando para mí, prueba este:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }

0
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

Llamar a este método sería muy bueno.

  1. No se requiere bucle.
  2. Si está utilizando animación en fragmentos, no mostrará demasiadas animaciones. Pero usando loop lo hará.

0
private boolean removeFragFromBackStack() {
    try {
        FragmentManager manager = getSupportFragmentManager();
        List<Fragment> fragsList = manager.getFragments();
        if (fragsList.size() == 0) {
            return true;
        }
        manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

Gracias por este fragmento de código, que puede proporcionar una ayuda limitada e inmediata. Una explicación adecuada mejoraría enormemente su valor a largo plazo al mostrar por qué esta es una buena solución al problema y la haría más útil para futuros lectores con otras preguntas similares. Por favor, editar su respuesta a añadir un poco de explicación, incluyendo los supuestos realizados.
Abdelilah El Aissaoui
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.