android - startactivity - ¿Cuáles son las diferencias entre FLAG_ACTIVITY_RESET_TASK_IF_NEEDED y FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP?
putextra android (3)
Estoy en el proceso de (finalmente) escribir el capítulo sobre tareas para mi libro, y estoy encontrando algunos acertijos persistentes.
Las cosas que sirven como FLAG_ACTIVITY_NEW_TASK
de pantalla de inicio parecen usar la combinación de FLAG_ACTIVITY_NEW_TASK
y FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
cuando FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
la actividad de FLAG_ACTIVITY_NEW_TASK
solicitada:
Intent i=new Intent(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_LAUNCHER);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
i.setComponent(name);
startActivity(i);
La documentación para FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
tiene:
Si se establece, y esta actividad se inicia en una nueva tarea o lleva a la cima una tarea existente, entonces se lanzará como la puerta de entrada de la tarea. Esto dará como resultado la aplicación de las afinidades necesarias para que la tarea se encuentre en el estado adecuado (ya sea moviendo actividades desde o hacia ella) o simplemente restableciendo esa tarea a su estado inicial si es necesario.
Eso no es especialmente claro.
En particular, parecería que se verían los mismos efectos usando una combinación de FLAG_ACTIVITY_CLEAR_TOP
y FLAG_ACTIVITY_SINGLE_TOP
. Citando los documentos para FLAG_ACTIVITY_CLEAR_TOP
:
Si se establece, y la actividad que se está iniciando ya se está ejecutando en la tarea actual, en lugar de lanzar una nueva instancia de esa actividad, todas las demás actividades que se encuentren encima se cerrarán y esta intención se entregará al (ahora encendido arriba) actividad anterior como un nuevo propósito ...
La instancia actualmente en ejecución de [la actividad deseada] recibirá el nuevo intento que está comenzando aquí en su método onNewIntent (), o se terminará y se reiniciará con el nuevo intento. Si ha declarado que su modo de lanzamiento es "múltiple" (el valor predeterminado) y no ha configurado FLAG_ACTIVITY_SINGLE_TOP en el mismo intento, entonces se terminará y se volverá a crear; para todos los demás modos de ejecución o si se establece FLAG_ACTIVITY_SINGLE_TOP, este Intent se entregará a la instancia actual onNewIntent ().
La documentación de FLAG_ACTIVITY_CLEAR_TOP
tiene sentido, al menos para mí.
Entonces, ¿qué hace FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
que sea diferente de la combinación de FLAG_ACTIVITY_CLEAR_TOP
y FLAG_ACTIVITY_SINGLE_TOP
?
Puntos de bonificación si puede explicar qué hace FLAG_ACTIVITY_CLEAR_TASK
diferente de cualquiera de las otras dos opciones descritas anteriormente.
Si se establece en un Intento pasado a Context.startActivity (), este indicador hará que cualquier tarea existente que esté asociada con la actividad se borre antes de que se inicie la actividad. Es decir, la actividad se convierte en la nueva raíz de una tarea que, de otro modo, estaría vacía, y todas las actividades anteriores finalizarán. Esto solo se puede usar junto con FLAG_ACTIVITY_NEW_TASK.
Una diferencia obvia entre esto y FLAG_ACTIVITY_CLEAR_TOP
| FLAG_ACTIVITY_SINGLE_TOP
es que FLAG_ACTIVITY_CLEAR_TASK
necesita FLAG_ACTIVITY_NEW_TASK
. Pero, aparte de eso, parecería que los efectos netos son los mismos, y también coinciden con FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
.
1) FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
Si alguna tarea está pendiente, destruirá ese proceso y comenzará la actividad que solicitó
2) FLAG_ACTIVITY_CLEAR_TOP
Si se está ejecutando algún intento previo de esta actividad, entonces este método entregará la instancia en ejecución de la actividad, cerrará todas las demás actividades y comenzará la actividad con la instancia anterior.
3) FLAG_ACTIVITY_SINGLE_TOP
Si recientemente se inició esta actividad y se guarda la instancia, no se iniciará esta actividad.
Eché un vistazo al código fuente del ActivityManager
. La bandera Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
hace algo de magia que Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
no funciona: desencadena tareas de reparación .
Aquí hay un ejemplo (aunque cojo):
En la aplicación A tenemos la raíz Actividad RootA
y tenemos otra actividad ReparentableA
:
<application
android:label="@string/app_name">
<activity android:name=".RootA">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ReparentableA"
android:allowTaskReparenting="true"/>
</application>
La aplicación A tiene el nombre del paquete "com.app.a", por lo que la taskAffinity
defecto de sus componentes es "com.app.a".
En la aplicación B tenemos la raíz de la actividad RootB
:
<application
android:label="@string/app_name">
<activity android:name="RootB">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
La aplicación B tiene el nombre del paquete "com.app.b", por lo que la taskAffinity
defecto de sus componentes es "com.app.b".
Ahora lanzamos la aplicación B desde la pantalla INICIO. Esto inicia una nueva tarea y crea una nueva instancia de Activity RootB
como la actividad raíz en esa tarea. Activity RootB
ahora lanza Activity ReparentableA
de la manera estándar, sin banderas especiales. Se ReparentableA
una instancia de ReparentableA
y se coloca encima de RootB
en la tarea actual.
Presione INICIO.
Ahora lanzamos la aplicación A desde la pantalla INICIO. Esto inicia una nueva tarea y crea una nueva instancia de Activity RootA
como la actividad raíz en esa tarea. NOTA: cuando Android inicia un Intento " Intent.FLAG_ACTIVITY_NEW_TASK
", establece automáticamente las banderas Intent.FLAG_ACTIVITY_NEW_TASK
e Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
. Debido a esto, el lanzamiento de RootA
ahora activa la reparación de tareas. Android busca ver si hay actividades en otras tareas que tienen afinidad con esta nueva tarea (y son reemplazables). Encuentra ReparentableA
(que tiene la misma afinidad de tarea que RootA
) en la tarea de la aplicación B y lo mueve a la nueva tarea de la aplicación A. Cuando lanzamos la Aplicación A no vemos RootA
, vemos realmente ReparentableA
, ya que se mueve a la parte superior de la nueva tarea.
Si volvemos a la aplicación B, podemos ver que ReparentableA
se ha ido de la pila de tareas y que ahora la tarea consiste en una sola actividad: RootB
.
Notas sobre el uso de Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
Lo importante que debe recordar sobre el uso de estos indicadores para "restablecer una tarea" es que solo funciona si ya hay una instancia de la actividad objetivo en la raíz de la tarea . Si su Actividad raíz siempre termina, no puede borrar su tarea iniciando la Actividad raíz con Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
. Android solo creará una nueva instancia de la Actividad de destino (raíz) y la colocará sobre las actividades existentes en la tarea , que probablemente no sea lo que usted desea.
Diferencia entre Intent.FLAG_ACTIVITY_CLEAR_TASK
e Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
:
Como se indicó anteriormente, al utilizar CLEAR_TOP | SINGLE_TOP
CLEAR_TOP | SINGLE_TOP
solo funciona si ya hay una instancia de la actividad objetivo en la tarea. CLEAR_TASK
, sin embargo, elimina todas las actividades de la tarea, independientemente de si hubo una instancia de la actividad objetivo en la tarea. Además, el uso de CLEAR_TASK
asegura que la Actividad objetivo se convierta en la Actividad raíz de la tarea, sin que usted tenga que saber qué Actividad era la Actividad raíz antes de borrar la tarea.
Diferencia entre Intent.FLAG_ACTIVITY_CLEAR_TASK
e Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
:
Como se indicó anteriormente, al usar CLEAR_TASK
siempre se eliminarán todas las actividades de la tarea y se lanzará una nueva instancia de la actividad objetivo. Por el contrario, RESET_TASK_IF_NEEDED
solo restablecerá la tarea en ciertas situaciones (la parte "IF_NEEDED"). La tarea solo se "restablece" si Android es:
- Crear una nueva tarea (en cuyo caso la funcionalidad "reiniciar" implica la reparación de tarea explicada anteriormente), o
- Si Android está llevando una tarea en segundo plano al primer plano (en cuyo caso, la tarea solo se borrará de las actividades que se lanzaron con
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
y cualquier actividad que esté en la parte superior de esas actividades). NOTA: La actividad raíz nunca se borra en este caso.
NOTA IMPORTANTE: Cuando realice la prueba, tenga en cuenta que existe una diferencia en el comportamiento de Android al iniciar aplicaciones desde la pantalla INICIO (o desde la lista de aplicaciones disponibles) y al seleccionar tareas de la lista de tareas recientes.
En el primer caso (al iniciar una aplicación seleccionándola de la lista de aplicaciones disponibles o de un acceso directo en la pantalla INICIO), se Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
con Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
Se crea Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
. Esto se usa independientemente de si la aplicación ya se está ejecutando o no. El Intent
se lanza y luego el ActivityManager
descubre qué hacer.
En el segundo caso (seleccionando una tarea de la lista de tareas recientes), si la tarea aún existe, simplemente se presenta al frente. La tarea "restablecer" NO se lleva a cabo si la tarea acaba de aparecer al frente usando la lista de tareas recientes. No es obvio para mí cómo se maneja esto y no he tenido la oportunidad de ver el código fuente para descubrir por qué.
Espero que esto responda a sus preguntas. Esperamos sus comentarios y resultados de las pruebas.
Puede que me equivoque aquí, pero en mi comprensión FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
analiza todas las tareas y se asegura de que solo se ejecute una tarea con actividad de FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
.
FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP
FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP
inspeccionará solo la tarea actual, por lo que podría terminar con 2 instancias de FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP
ejecutándose al mismo tiempo (si la primera se creó como una tarea separada).