Reanudación múltiple

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

  • Se inició una nueva actividad translúcida sobre la app, mientras esta aún era visible (y, por lo tanto, no se detuvo).
  • La actividad perdió el enfoque, pero no se ocultó y el usuario pudo interactuar con ella. Por ejemplo, en el modo multiventana, varias actividades pueden ser visibles 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 las 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 la pantalla dividida.
  • Se reanudan todas las actividades visibles en la parte superior 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 modo de computadora

Las actividades pueden residir en el estado PAUSED cuando no se pueden enfocar o están parcialmente ocluidas, por ejemplo:

  • En una pantalla dividida minimizada (con el selector al costado), 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 otras actividades transparentes de la misma pila cubren las actividades.

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

Para preservar 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, se llama a esta devolución de llamada 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. Debido a que esta devolución de llamada es opcional, no forma parte del ciclo de vida de la actividad y debe usarse con poca frecuencia.

La actividad anterior reanudada recibe y finaliza la ejecución de onTopResumedActivity(false) antes de que la siguiente actividad reanudada 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 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 objetos singleton.
  • 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 orientadas a 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 en pantalla completa y reanudada puede perder el enfoque de la cámara para una actividad en pausa en la parte superior en el modo de pantalla en pantalla, pero se vuelve más expuesta con una adopción más amplia de los modos multiventana y de pantallas múltiples.
    • Debido a los cambios realizados en el estado RESUME, es posible que las apps se desconecten de la cámara incluso mientras se reanudan. Para solucionar este problema, las apps deben controlar una 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 usándola. 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) cambia 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 en Z. Para asegurarte de que el estado correcto después de las actualizaciones de visibilidad en una actividad y evaluar qué estado de 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, se realiza un seguimiento independiente de la reanudación de una actividad 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 actividad reanudada

Después de las acciones que pueden provocar un cambio en la actividad principal (como el inicio, la reanudación o el cambio de orden en Z de la actividad), se invoca ActivityStackSupervisor#updateTopResumedActivityIfNeeded(). Este método verifica si cambió la actividad reanudada más alta y realiza la actualización si es necesario. Si la actividad anterior que se reanuda no liberó el estado de reanudación, se le envía un mensaje de pérdida de estado de reanudación y se programa un tiempo de espera del servidor (ActivityStackSupervisor#scheduleTopResumedStateLossTimeout()). Se envía un informe del estado de reanudación 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 los cambios de estado reanudados más importantes y aprovecha la arquitectura ActivityLifecycler de Android 9.

El estado reanudado superior se almacena en el 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 cierta desvinculación en la comunicación de los estados del ciclo de vida y el estado reanudado superior entre el servidor y el cliente.