Reanudación múltiple

En Android 9 (y versiones anteriores), las apps entraban en el estado PAUSED en los siguientes casos:

  • Se inició una nueva actividad traslúcida sobre la app, mientras esta seguía visible (y, por lo tanto, no se detuvo).
  • La actividad perdió el enfoque, pero no estaba obstruida y el usuario podía interactuar con ella. Por ejemplo, en el modo multiventana, se pueden ver varias actividades y recibir entradas táctiles de forma simultánea.

Estas situaciones difieren en la cantidad de pausas que debe realizar una app, pero no se pueden distinguir a nivel de la app.

En Android 10, todas las actividades enfocables principales en pilas visibles residen en el estado RESUMED. Esto mejora la compatibilidad con los modos multiventana y MD para las apps que usan onPause() en lugar de onStop() para dejar de actualizar la IU y de interactuar con el usuario. Esto significa lo siguiente:

  • Se reanudan ambas actividades en pantalla dividida.
  • Se reanudan todas las actividades visibles en primer plano en el modo de ventanas de formato libre.
  • Las actividades en varias pantallas se pueden reanudar al mismo tiempo.

Figura 1: Reanudación múltiple en un dispositivo plegable

Figura 2: Reanudación múltiple en el modo de escritorio

Las actividades pueden residir en el estado PAUSED cuando no se pueden enfocar o están parcialmente obstruidas, como en los siguientes casos:

  • En una pantalla dividida minimizada (con el selector en el lateral), no se reanuda la actividad superior porque no se puede enfocar.
  • En el modo de pantalla en pantalla, la actividad no se reanuda porque no se puede enfocar.
  • Cuando las actividades están cubiertas por otras actividades transparentes en la misma pila

Este enfoque indica a las apps que una actividad solo puede recibir entrada de un usuario en el estado RESUMED. Antes de Android 10, las actividades también podían recibir entrada en el estado PAUSED (por ejemplo, intenta tocar ambas actividades en pantalla dividida de forma simultánea en un dispositivo que ejecute Android 9).

Para conservar el indicador reanudado de versiones anteriores de Android (y para comunicar cuándo las apps deben obtener acceso a recursos de acceso exclusivo o singleton), Android 10 incluye una nueva devolución de llamada:

Activity#onTopResumedActivityChanged(boolean onTop)

Cuando se invoca, esta devolución de llamada se llama entre Activity#onResume() y Activity#onPause(). Esta devolución de llamada es opcional y se puede omitir, por lo que una actividad puede pasar de un estado RESUMED a un estado PAUSED sin convertirse en la principal del sistema. Por ejemplo, en el modo multiventana. Como esta devolución de llamada es opcional, no forma parte del ciclo de vida de la actividad y se debe usar con poca frecuencia.

La actividad anterior en la parte superior que se reanudó recibe y finaliza la ejecución de onTopResumedActivity(false) antes de que la siguiente actividad en la parte superior que se reanudó reciba onTopResumedActivity(true), a menos que la actividad anterior tarde demasiado en controlar la llamada al método y alcance el tiempo de espera de 500 ms.

Compatibilidad

Para mantener la compatibilidad cuando implementes la reanudación múltiple, considera estas soluciones.

Varias actividades reanudadas en un proceso de la app

  • Problema. En Android 9 y versiones anteriores, solo se reanuda una actividad en el sistema a la vez. Todas las transiciones entre actividades implican pausar una actividad antes de reanudar otra. Algunas apps y frameworks (como Flutter o LocalActivityManager de Android) usan este hecho y almacenan el estado de la actividad reanudada en singletons.
  • Solución. En Android 9 y versiones anteriores, si se reanudan dos actividades del mismo proceso, el sistema solo reanuda la actividad que tiene un orden Z más alto. Las apps que segmentan Android 10 pueden admitir que se reanuden varias actividades al mismo tiempo.

Acceso simultáneo a la cámara

  • Problemas. Estos problemas también están presentes en Android 9 y versiones anteriores. Por ejemplo, una actividad reanudada y en pantalla completa puede perder el enfoque de la cámara ante una actividad pausada en la parte superior en el modo de pantalla en pantalla, pero quedar más expuesta con una mayor adopción de los modos multiventana y de pantallas múltiples.
    • Debido a los cambios realizados en el estado de RESUME, es posible que las apps se desconecten de la cámara incluso mientras se reanudan. Para solucionar este problema, las apps deben controlar la desconexión de la cámara sin fallar. Cuando se desconectan, las apps reciben una devolución de llamada de desconexión y todas las llamadas a la API comienzan a arrojar CameraAccessException.
    • resizeableActivity=false no es una garantía de acceso exclusivo a la cámara, ya que otras apps que la utilizan se pueden abrir en otras pantallas.
  • Soluciones. Los desarrolladores deben incluir lógica para cuando una app se desconecta de la cámara. Si una app se desconecta de la cámara, debe observar las devoluciones de llamada de disponibilidad de la cámara para intentar volver a conectarse y seguir usando la cámara. Además de la devolución de llamada CameraManager#AvailabilityCallback#onCameraAvailable() existente, Android 10 agregó CameraManager#AvailabilityCallback#onCameraAccessPrioritiesChanged(), que abarca el caso en el que el enfoque (y la prioridad de la cámara) cambian entre varias actividades reanudadas. Los desarrolladores de apps deben usar ambas devoluciones de llamada para determinar un buen momento para intentar acceder a la cámara.

Reanudación múltiple

En Android 10, el estado del ciclo de vida de la actividad se determina según la visibilidad y el orden Z. Para asegurarte de que el estado sea correcto después de las actualizaciones de visibilidad en una actividad y evaluar qué estado del ciclo de vida es aplicable, invoca el método ActivityRecord#makeActiveIfNeeded() desde diferentes ubicaciones. En Android 10, activo significa RESUMED o PAUSED, y solo funciona en estas dos instancias.

En Android 10, la reanudación de una actividad se realiza un seguimiento por separado en cada pila en lugar de en la única ubicación del sistema. Esto se debe a que se pueden realizar varias transiciones de actividad de forma simultánea en los modos multiventana. Para obtener más detalles, consulta ActivityStack#mInResumeTopActivity.

Devolución de llamada de la actividad que se reanudó en primer lugar

Después de las acciones que pueden provocar un cambio en la actividad superior (como el inicio, la reanudación o el cambio de orden Z de la actividad), se invoca ActivityStackSupervisor#updateTopResumedActivityIfNeeded(). Este método verifica si cambió la actividad más reanudada y realiza la actualización si es necesario. Si la actividad anterior que se reanudó en primer plano no liberó el estado de reanudación en primer plano, se le envía un mensaje de pérdida de estado de reanudación en primer plano y se programa un tiempo de espera en el servidor (ActivityStackSupervisor#scheduleTopResumedStateLossTimeout()). Se envía un informe del estado de reanudación en primer plano a la siguiente actividad después de que la anterior liberó el estado o cuando se alcanzó un tiempo de espera (consulta los usos de:

ActivityStackSupervisor#scheduleTopResumedActivityStateIfNeeded()

Se agregó un nuevo elemento de transacción TopResumedActivityChangeItem para informar a los clientes sobre los cambios de estado de reanudación principales y aprovecha la arquitectura ActivityLifecycler de Android 9.

El estado de reanudación superior se almacena del lado del cliente y, cada vez que la actividad pasa a RESUMED o PAUSED, también se verifica si se debe invocar la devolución de llamada onTopResumedActivityChanged(). Esto permite cierto desacoplamiento en la comunicación de los estados del ciclo de vida y el estado de reanudación superior entre el servidor y el cliente.