Reanudación múltiple

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

  • Se inició una actividad nueva y 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 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 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 un selector lateral), no se reanuda la actividad superior porque no es enfocable.
  • En el modo de pantalla en pantalla, no se reanuda la actividad porque no es enfocable.
  • Cuando las actividades están cubiertas por otras actividades transparentes de la misma pila

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

Activity#onTopResumedActivityChanged(boolean onTop)

Cuando se invoca, esta devolución de llamada se realiza 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 debe usarse con poca frecuencia.

La actividad más reanudada anterior recibe y finaliza la ejecución de onTopResumedActivity(false) antes de que la siguiente actividad más reanudada reciba onTopResumedActivity(true), a menos que la actividad anterior tarde mucho tiempo en controlar la llamada de 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 está más alta en el orden en Z. 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 una reanudada puede perder el enfoque de la cámara ante una actividad pausada en la parte superior en el modo de pantalla en pantalla, pero estar más expuesta con una adopción más amplia de los modos multiventana y de varias pantallas.
    • 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 está determinado por la visibilidad y el orden en Z. Para asegurarte de que el estado correcto después de que se actualice la 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, la reanudación de una actividad se rastrea por separado en cada pila y no 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 superior

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 arriba y realiza la actualización si es necesario. Si la actividad anterior que se reanuda en la parte superior no liberó el estado de reanudación superior, se le envía un mensaje de pérdida de estado de reanudación superior y se programa un tiempo de espera del servidor (ActivityStackSupervisor#scheduleTopResumedStateLossTimeout()). Se envía un informe del estado de reanudación superior 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 principales 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.