Límites de ejecución en segundo plano

Cada vez que una app se ejecuta en segundo plano, consume algunos de los recursos limitados del dispositivo, como la RAM. Esto puede afectar la experiencia del usuario, en especial si usa una app que usa muchos recursos, como un videojuego o mirando un video. Para mejorar la experiencia del usuario, Android 8.0 (nivel de API 26) impone limitaciones en lo que pueden hacer las apps mientras se ejecutan en segundo plano. En este documento, se describen los cambios en el sistema operativo y cómo puedes actualizar tu app para que funcione bien con las nuevas limitaciones.

Descripción general

Muchas apps y servicios de Android se pueden ejecutar de manera simultánea. Por ejemplo, un usuario podría jugar un juego en una ventana mientras navega en la Web desde otra, y usar una tercera app para reproducir música. Cuantas más apps se ejecuten a la vez, más carga se realizará en el sistema. Si se ejecutan apps o servicios adicionales en segundo plano, se generan más cargas en el sistema, lo que podría generar una mala experiencia del usuario (por ejemplo, la app de música podría cerrarse repentinamente).

Para disminuir las probabilidades de tener estos problemas, Android 8.0 establece limitaciones sobre lo que pueden hacer las apps mientras los usuarios no interactúan directamente con ellas. Existen dos clases de restricciones para apps:

  • Limitaciones del servicio en segundo plano: Mientras una app se encuentra inactiva, existen límites para el uso de los servicios en segundo plano. Esto no se aplica a los servicios en primer plano, que son más notorios para el usuario.

  • Limitaciones de transmisión: Con excepciones limitadas, las apps no pueden usar su manifiesto para registrarse para transmisiones implícitas. Pueden registrarse para estas transmisiones durante el tiempo de ejecución y usar el manifiesto a fin de registrarse para transmisiones y transmisiones explícitas destinadas específicamente a su app.

En la mayoría de los casos, las apps pueden resolver estas limitaciones con trabajos JobScheduler. Este enfoque permite que un arreglo de apps realice tareas cuando esta no se está ejecutando de forma activa, pero le brinda al sistema la libertad de programar esas tareas de una manera que no afecte la experiencia del usuario. Android 8.0 ofrece varias mejoras a JobScheduler, que facilitan el reemplazo de servicios y receptores de emisión por tareas programadas. Para obtener más información, consulta Mejoras de JobScheduler.

Limitaciones del servicio en segundo plano

Los servicios que se ejecutan en segundo plano pueden consumir recursos del dispositivo, lo que podría empeorar la experiencia del usuario. Para mitigar este problema, el sistema aplica una serie de limitaciones en los servicios.

El sistema distingue entre apps en primer plano y en segundo plano. (La definición de segundo plano en relación con las limitaciones del servicio es distinta de la que usa la administración de memoria; una app puede estar en segundo plano en lo que respecta a la administración de memoria, pero en primer plano en lo que respecta a su capacidad para lanzar servicios). Se considera que una aplicación se encuentra en primer plano si alguno de los siguientes puntos se cumple:

  • Tiene una actividad visible, independientemente de esta última se haya iniciado o esté en pausa.
  • Tiene un servicio en primer plano.
  • Otra app en primer plano está conectada a la app, ya sea mediante la vinculación a uno de sus servicios o el uso de uno de sus proveedores de contenido. Por ejemplo, la app está en primer plano si otra se vincula a lo siguiente:
    • IME
    • servicio de fondo de pantalla;
    • Receptor de notificaciones
    • servicio de voz o texto.

Si no se cumple ninguna de esas condiciones, se considera que la app se encuentra en segundo plano.

Mientras una app se encuentra en primer plano, puede crear y ejecutar servicios en primer y segundo plano libremente. Cuando una app pasa a segundo plano, tiene una ventana de varios minutos durante los cuales puede crear y usar servicios. Al final de esa ventana, la app se considera inactiva. En este momento, el sistema detiene los servicios en segundo plano de la app, como si esta hubiera llamado a los métodos Service.stopSelf() de los servicios.

En determinadas circunstancias, una app en segundo plano se coloca en una lista de entidades permitidas temporal durante varios minutos. Mientras una app está en la lista de entidades permitidas, puede iniciar servicios sin limitaciones, y se permite la ejecución de sus servicios en segundo plano. Una app se ubica en la lista de entidades permitidas cuando controla una tarea que es visible para el usuario, por ejemplo:

En muchos casos, tu app puede reemplazar servicios en segundo plano por trabajos JobScheduler. Por ejemplo, CoolPhotoApp debe verificar si el usuario recibió fotos compartidas de amigos, incluso si la app no se está ejecutando en primer plano. Anteriormente, la app usaba un servicio en segundo plano que se verificaba con su almacenamiento en la nube. Para migrar a Android 8.0 (nivel de API 26), el desarrollador reemplaza el servicio en segundo plano por una tarea programada, que se inicia periódicamente, realiza consultas al servidor y, luego, se cierra.

Antes de Android 8.0, el modo usual de crear un servicio en primer plano era crear uno en segundo plano y, luego, promoverlo a primer plano. Con Android 8.0, existe una complicación: el sistema no permite que una app en segundo plano cree un servicio en segundo plano. Por este motivo, Android 8.0 presenta el nuevo método startForegroundService() para iniciar un servicio nuevo en primer plano. Después de que el sistema crea el servicio, la app tiene cinco segundos para llamar al método [startForeground()](/reference/android/app/Service#startForeground(int, android.app.Notification) del servicio para mostrar la notificación visible para el usuario del servicio nuevo. Si la app no llama a startForeground() dentro del límite de tiempo, el sistema detiene el servicio y declara que la app tiene un estado de ANR.

Limitaciones de transmisión

Si una app se registra para recibir transmisiones, su receptor consume recursos cada vez que se envía. Esto puede causar problemas si demasiadas apps se registran para recibir transmisiones en función de los eventos del sistema; un evento del sistema que activa una transmisión puede hacer que todas esas apps consuman recursos con rapidez, lo que afectaría la experiencia del usuario. Para mitigar este problema, Android 7.0 (nivel de API 24) aplicó limitaciones a las transmisiones, como se describe en Optimización en segundo plano. Android 8.0 (nivel de API 26) hace que esas limitaciones sean más estrictas.

  • Las apps orientadas a Android 8.0 o versiones posteriores ya no pueden registrar receptores de emisión para transmisiones implícitas en su manifiesto, a menos que la transmisión esté específicamente restringida a esa app. Una transmisión implícita es una transmisión que no se orienta a un componente específico dentro de una app. Por ejemplo, ACTION_PACKAGE_REPLACED se envía a todos los objetos de escucha registrados en todas las apps para informarles que se reemplazó algún paquete en el dispositivo. Como la transmisión está implícita, no se entregará a receptores registrados en manifiestos en apps orientadas a Android 8.0 o versiones posteriores. ACTION_MY_PACKAGE_REPLACED también es una transmisión implícita, pero como se envía solo a la app cuyo paquete se reemplazó, se entregará a receptores registrados en el manifiesto.
  • Las apps pueden continuar registrándose para transmisiones explícitas en sus manifiestos.
  • Las apps pueden usar Context.registerReceiver() durante el tiempo de ejecución a fin de registrar un receptor para cualquier transmisión, ya sea implícita o explícita.
  • Las transmisiones que requieren un permiso de firma quedan exentas de esta restricción, ya que solo se envían a apps que están firmadas con el mismo certificado, no a todas las apps del dispositivo.

En muchos casos, las apps que se registraron previamente para una transmisión implícita pueden obtener una funcionalidad similar mediante un trabajo JobScheduler. Por ejemplo, es posible que una app social de fotos necesite realizar una limpieza de sus datos ocasionalmente y prefiera hacerlo cuando el dispositivo está conectado a un cargador. Anteriormente, la app registraba un receptor para ACTION_POWER_CONNECTED en su manifiesto; cuando recibía esa transmisión, comprobaba si la limpieza era necesaria. Para migrar a Android 8.0 o versiones posteriores, la app quita ese receptor del manifiesto. En cambio, la app programa un trabajo de limpieza que se ejecuta cuando el dispositivo está inactivo y cargándose.

Guía de migración

De forma predeterminada, estos cambios solo afectan a las apps orientadas a Android 8.0 (nivel de API 26) o versiones posteriores. Sin embargo, los usuarios pueden habilitar estas restricciones para cualquier app desde la pantalla Configuración, incluso si la app se orienta a un nivel de API inferior al 26. Es posible que debas actualizar tu app para que cumpla con las nuevas limitaciones.

Comprueba el modo en que tu app usa los servicios. Si tu app depende de servicios que se ejecutan en segundo plano mientras está inactiva, deberás reemplazarlos. Entre las posibles soluciones, se incluyen las siguientes:

  • Si tu app necesita crear un servicio en primer plano mientras está en segundo plano, usa el método startForegroundService() en lugar de startService().
  • Si el servicio es visible para el usuario, haz que funcione en primer plano. Por ejemplo, un servicio que reproduce audio siempre debe ser un servicio en primer plano. Crea el servicio con el método startForegroundService() en lugar de startService().
  • Encuentra una manera de duplicar la funcionalidad del servicio con una tarea programada. Si el servicio no hace algo que sea notorio de inmediato para el usuario, por lo general, deberías poder usar un trabajo programado en su lugar.
  • Usa FCM para activar tu aplicación de forma selectiva cuando se produzcan eventos de red, en lugar de sondear en segundo plano.
  • Difiere tareas en segundo plano hasta que la aplicación se encuentre naturalmente en primer plano.

Revisa los receptores de emisión definidos en el manifiesto de tu app. Si tu manifiesto declara un receptor para una transmisión implícita afectada, debes reemplazarlo. Entre las posibles soluciones, se incluyen las siguientes:

  • Para crear el receptor en el tiempo de ejecución, llama a Context.registerReceiver(), en lugar de declarar el receptor en el manifiesto.
  • Usa un trabajo programado para verificar la condición que habría activado la transmisión implícita.