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 consume muchos recursos, como un juego o mirando un video. Para mejorar la experiencia del usuario, Android 8.0 (nivel de API 26) impone limitaciones en lo que las apps pueden hacer 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 en una ventana mientras navega en la Web en otra, y usar una tercera app para reproducir música. Cuantas más apps se ejecuten a la vez, mayor carga se generará 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 reducir 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 está 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 en transmisiones implícitas. Pueden registrarse para esas transmisiones durante el tiempo de ejecución y usar los manifiestos a fin de registrarse en 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 trabajos 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 con 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 las apps en primer plano y en segundo plano. (La definición de segundo plano a los efectos de 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 por vinculación a uno de sus servicios o por el uso de uno de sus proveedores de contenido. Por ejemplo, la app se encuentra 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 está 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 en los que aún 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 ubica en una lista de entidades permitidas temporal durante varios minutos. Mientras una app esté en la lista de entidades permitidas, podrá lanzar servicios sin limitarse a ello, y sus servicios en segundo plano pueden ejecutarse. 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 necesita 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 el almacenamiento en la nube de la app. 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 de forma periódica, 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, hacer que pase a funcionar en primer plano. Con Android 8.0, existe una complicación: el sistema no permite que una app que está en segundo plano cree un servicio en segundo plano. Por esta razón, 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 la transmisión. 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 rápidamente, lo que afectaría la experiencia del usuario. Para mitigar este problema, Android 7.0 (nivel de API 24) impuso limitaciones en 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é restringida específicamente 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, lo que les permite saber que se reemplazó algún paquete en el dispositivo. Debido a que la transmisión es implícita, no se entregará a receptores registrados en el manifiesto 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 los 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 están exentas de esta restricción, ya que solo se envían a las 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 con un trabajo de JobScheduler. Por ejemplo, es posible que una app social de fotos deba 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, 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 a 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 debe ser siempre 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.
  • Usa FCM para activar tu aplicación de manera selectiva cuando se produzcan eventos de red, en lugar de realizar sondeos 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:

  • Crea el receptor en el tiempo de ejecución llamando a Context.registerReceiver(), en lugar de declarar el receptor en el manifiesto.
  • Usa una tarea programada para buscar la condición que habría activado la transmisión implícita.