¿Cómo se usa Intent.FLAG_ACTIVITY_CLEAR_TOP para borrar la pila de actividades?

84

He leído varias publicaciones sobre el uso de esto, pero debe faltar algo ya que no me funciona. Mi actividad A tiene launchmode = "singleTop" en el manifiesto. Inicia la actividad B, con launchmode = "singleInstance". La actividad B abre un navegador y recibe una intención de regreso, por lo que es singleInstance. Estoy tratando de anular el botón Atrás para que el usuario vuelva a la actividad A y luego pueda presionar Atrás para dejar la actividad, en lugar de volver a la actividad B nuevamente.

// activity B
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)  {
 if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR
  && keyCode == KeyEvent.KEYCODE_BACK
  && event.getRepeatCount() == 0) onBackPressed();
 return super.onKeyDown(keyCode, event);
}
@Override
public void onBackPressed() {
 startActivity(new Intent(this, UI.class)
 .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
 return;
}

Después de regresar del navegador, la pila es ... A, B, Browser, B

Espero que este código cambie la pila a ... A ... para que al presionar atrás una vez más, el usuario regrese a la pantalla de inicio.

En cambio, parece cambiar la pila a ... A, B, Navegador, B, A ... como si esas banderas no estuvieran allí.

Intenté llamar a finish () en la actividad B después de startActivity, ¡pero luego el botón de retroceso me lleva de nuevo al navegador!

¿Qué me estoy perdiendo? ¡Gracias!

piusvelte
fuente

Respuestas:

72

@bitestar tiene la solución correcta, pero hay un paso más:

Estaba escondido en los documentos, sin embargo, debe cambiar el launchModede Activitya cualquier otro que no sea standard. De lo contrario, será destruido y recreado en lugar de restablecerse a la cima.

ScouseChris
fuente
51
En realidad ... Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOPharé precisamente eso.
Derk-Jan
Consulte la solución de Steel_fedex para ver su ejemplo.
Darpan
2
Entonces, ¿dónde diablos está la solución de Steel_fedex?
ChangWon Jeong Juicycool
112

Comencé la Actividad A-> B-> C-> D. Cuando se presiona el botón Atrás en la Actividad DI, quiero ir a la Actividad A. Dado que A es mi punto de partida y, por lo tanto, ya están en la pila, todas las actividades en la parte superior de A se borran y no puede volver a ninguna otra Actividad de A .

Esto realmente funciona en mi código:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        Intent a = new Intent(this,A.class);
        a.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(a);
        return true;
    }
    return super.onKeyDown(keyCode, event);
}       
Jesper Bischoff-Jensen
fuente
4
Esta solución cierra todas las actividades intermedias; pero también, reiniciando RootActivity. Puede consultar la solución de @ Steel_Fedex a continuación. Hace lo mismo, pero no reinicia RootActivity.
Darpan
Esta es la mejor solución para mi caso. De hecho, quiero que la actividad raíz se inicie nuevamente
Tash Pemhiwa
24

Para esto, uso la FLAG_ACTIVITY_CLEAR_TOPbandera para comenzar Intent
(sin FLAG_ACTIVITY_NEW_TASK)

y launchMode = "singleTask"en manifiesto para la actividad iniciada.

Parece que funciona como necesito: la actividad no se reinicia y todas las demás actividades están cerradas.

Fedir Tsapana
fuente
Lo comprobé, la solución de Bitster no funciona. Mientras esta solución funcionó. RootActivity no se reinició.
Darpan
Elija sus palabras con más sabiduría. ¡La solución Bitestar realmente funciona!
Jesper Bischoff-Jensen
singleTask funciona para mí, por lo que la actividad no se volverá a crear ni manejará el evento en onNewIntent.
Jishi Chen
11

Aunque esta pregunta ya tiene suficientes respuestas, pensé que alguien querría saber por qué esta bandera funciona de esta manera peculiar. Esto es lo que encontré en la documentación de Android.

La instancia actualmente en ejecución de la actividad B en el ejemplo anterior recibirá la nueva intención que está comenzando aquí en su método onNewIntent (), o se terminará y reiniciará con la nueva intención.

Si ha declarado que su modo de lanzamiento es "múltiple" (el predeterminado) y no ha configurado FLAG_ACTIVITY_SINGLE_TOP con la misma intención, entonces se terminará y se volverá a crear; para todos los demás modos de lanzamiento o si se establece FLAG_ACTIVITY_SINGLE_TOP, este Intent se entregará al onNewIntent () de la instancia actual.


Entonces, O bien,
1 . Cambie el launchModede la Actividad A por algo diferente del estándar (es decir, singleTasko algo). Entonces su bandera FLAG_ACTIVITY_CLEAR_TOPno reiniciará su Actividad A.

o,

2 . Úselo Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOPcomo su bandera. Entonces funcionará de la manera que desee.

Darpan
fuente
8

Utilizo tres banderas para resolver el problema:

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
                Intent.FLAG_ACTIVITY_CLEAR_TASK | 
                Intent.FLAG_ACTIVITY_NEW_TASK);
Houssin Boulla
fuente
4

Agregue android: noHistory = "true" en el archivo de manifiesto.

<manifest >
        <activity
            android:name="UI"
            android:noHistory="true"/>

</manifest>
Ahmad Aghazadeh
fuente
La primera vez que veo esta bandera, pero funcionó para mi caso, gracias
vlasentiy
3

Llamé activity_name.this.finish()después de comenzar una nueva intención y funcionó para mí.

I tried "FLAG_ACTIVITY_CLEAR_TOP" and "FLAG_ACTIVITY_NEW_TASK"

Pero no funcionará para mí ... No estoy sugiriendo esta solución para su uso, pero si la configuración de la bandera no funciona para usted, puede probar esto ... pero aún así recomiendo no usarlo

Swap-IOS-Android
fuente
2

Sé que ya hay una respuesta aceptada, pero no veo cómo funciona para el OP porque no creo que FLAG_ACTIVITY_CLEAR_TOP sea significativo en su caso particular. Esa bandera es relevante solo con actividades en la misma tarea . Según su descripción, cada actividad tiene su propia tarea. : A, B y el navegador.

Algo que quizás lo desconcierta es que A es singleTop, cuando debería ser singleTask. Si A es singleTop, y B inicia A, entonces se creará una nueva A porque A no está en la tarea de B. De la documentación de singleTop:

"Si ya existe una instancia de la actividad en la parte superior de la tarea actual , el sistema enruta la intención a esa instancia ..."

Dado que B inicia A, la tarea actual es la tarea de B, que es para una sola instancia y, por lo tanto, no puede incluir A. Use singleTask para lograr el resultado deseado allí porque entonces el sistema encontrará la tarea que tiene A y traerá esa tarea al primer plano.

Por último, después de que B haya iniciado A, y el usuario presione hacia atrás desde A, el OP no quiere ver ni B ni el navegador. Para lograr esto, llamar a finish () en B es correcto; nuevamente, FLAG_ACTIVITY_CLEAR_TOP no eliminará las otras actividades en la tarea de A porque sus otras actividades están todas en tareas diferentes. Sin embargo, la pieza que le faltaba es que B también debería usar FLAG_ACTIVITY_NO_HISTORY al disparar la intención para el navegador. Nota: si el navegador ya se está ejecutando incluso antes de iniciar la aplicación del OP, entonces, por supuesto, verá el navegador al presionar hacia atrás desde A. Entonces, para probar esto realmente, asegúrese de salir del navegador antes de iniciar la aplicación.

Kevin
fuente
1

FLAG_ACTIVITY_NEW_TASK es el problema aquí que inicia una nueva tarea. Simplemente elimínelo y listo.

Bueno, te recomiendo que leas lo que hacen todas las banderas antes de trabajar con ellas.

Lea esto y las banderas de intención aquí

100rabh
fuente
1
Leí la bandera y sonaba como lo que necesitaba. Independientemente, eliminar FLAG_ACTIVITY_NEW_TASK no tiene ningún efecto en el resultado. Sigue siendo un bucle de botón de retroceso sin fin ... A-> B, de regreso a A, de regreso a B, de regreso a A ...
piusvelte
¿Estás seguro de por qué estás usando B como singleInstance? La actividad AA "singleInstance" actúa como si FLAG_ACTIVITY_NEW_TASK estuviera en el intent.Check developer.android.com/guide/topics/fundamentals.html
100rabh
B necesita recibir la llamada de intent desde el navegador. Intenté cambiar el modo de lanzamiento a singleTask, y todavía funciona, pero el bucle del botón Atrás aún se produce.
piusvelte
Creo que no funcionó porque usó FLAG_ACTIVITY_NEW_TASK allí. Mejor use solo FLAG_ACTIVITY_CLEAR_TOP y evite usar ni singleTask ni singleInstance
100rabh
1
Creo que debería ser una solución funcional, si agrega Intent.FLAG_ACTIVITY_SINGLE_TOPpara evitar la recreación
yonojoy
1

Inicialmente, también tuve problemas para que FLAG_ACTIVITY_CLEAR_TOP funcionara. Eventualmente lo hice funcionar usando su valor (0x04000000). Parece que hay un problema de Eclipse / compilador. Pero, lamentablemente, se reinicia la actividad superviviente, que no es lo que quiero. Parece que no hay una solución fácil.

ja_chu
fuente