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, sobre todo si está usando una app que requiere muchos recursos, como jugar un videojuego o mirar 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 estar jugando un juego en una ventana mientras navega por la Web en otra y usa una tercera app para reproducir música. Cuantas más apps se ejecuten a la vez, más carga se colocará en el sistema. Si se ejecutan apps o servicios adicionales en segundo plano, se agregan cargas adicionales al sistema, lo que podría generar una experiencia del usuario deficiente. Por ejemplo, la app de música podría cerrarse de forma repentina.
Para reducir las posibilidades de que ocurran estos problemas, Android 8.0 impone limitaciones a lo que las apps pueden hacer 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 servicios en segundo plano. Esto no se aplica a los servicios en primer plano, que son más perceptibles para el usuario.
Limitaciones de transmisión: Con excepciones limitadas, las apps no pueden usar su manifiesto para registrarse en transmisiones implícitas. De todas maneras, pueden registrarse para estas transmisiones en el tiempo de ejecución y usar el manifiesto para registrarse en transmisiones explícitas y transmisiones segmentadas específicamente para su app.
En la mayoría de los casos, las apps pueden evitar estas limitaciones con el uso de trabajos JobScheduler
. Este enfoque permite que una app se organice para realizar tareas cuando no se está ejecutando de forma activa, pero aún le da al sistema la flexibilidad para programar estas tareas de una manera que no afecte la experiencia del usuario. Android 8.0 ofrece varias mejoras en JobScheduler
que facilitan el reemplazo de servicios y receptores de emisión con trabajos programados. 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 generar una experiencia del usuario más deficiente. Para mitigar este problema, el sistema aplica una serie de limitaciones a los servicios.
El sistema distingue entre las apps en primer plano y en segundo plano. (La definición de segundo plano para los fines de las limitaciones del servicio es distinta de la definición 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 iniciar 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.
- Si otra app en primer plano está conectada a la app, ya sea por vinculación de uno de sus servicios o uso de uno de sus proveedores de contenido. Por ejemplo, la app está en primer plano si otra app 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, entonces 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 con libertad. Cuando una app pasa a segundo plano, tiene un período de varios minutos en el que aún puede crear y usar servicios. Al final de esa ventana, se considera que la app está 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 ciertas 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 sus servicios en segundo plano pueden ejecutarse. Una app se coloca en la lista de entidades permitidas cuando controla una tarea que es visible para el usuario, como las siguientes:
- Controla un mensaje de Firebase Cloud Messaging (FCM) de prioridad alta.
- recibir una transmisión, como un mensaje SMS o MMS.
- Ejecutar un
PendingIntent
desde una notificación - Iniciar un
VpnService
antes de que la app de VPN se promocione a primer plano
En muchos casos, tu app puede reemplazar los servicios en segundo plano por tareas de 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 verificaba 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 periódicamente, consulta el servidor y, luego, se cierra.
Antes de Android 8.0, la forma habitual de crear un servicio en primer plano era crear un servicio en segundo plano y, luego, promocionarlo al primer plano.
Con Android 8.0, hay 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 nuevo servicio 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 error ANR.
Limitaciones de transmisión
Si una app se registra para recibir emisiones, el receptor de la app consume recursos cada vez que se envía la emisión. Esto puede causar problemas si demasiadas apps se registran para recibir transmisiones basadas en eventos del sistema. Un evento del sistema que activa una transmisión puede hacer que todas esas apps consuman recursos en rápida sucesión, lo que perjudica la experiencia del usuario. Para mitigar este problema, Android 7.0 (nivel de API 24) estableció 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 que se orientan a Android 8.0 o versiones posteriores ya no pueden registrar receptores de emisión para emisiones implícitas en su manifiesto, a menos que la emisión esté restringida a esa app específicamente. Una transmisión implícita es una transmisión que no se segmenta para 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 es implícita, no se entregará a los receptores registrados en el manifiesto en las apps que se orienten a Android 8.0 o versiones posteriores.ACTION_MY_PACKAGE_REPLACED
también es una transmisión implícita, pero como solo se envía 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 para 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 estas transmisiones 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 anteriormente para una transmisión implícita pueden obtener una funcionalidad similar con un trabajo JobScheduler
.
Por ejemplo, es posible que una app de fotos de redes sociales deba limpiar sus datos de vez en cuando 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 la app recibía esa transmisión, verificaba si era necesaria la limpieza. Para migrar a Android 8.0 o versiones posteriores, la app quita ese receptor de su manifiesto. En su lugar, la app programa un trabajo de limpieza que se ejecuta cuando el dispositivo está inactivo y se está cargando.
Guía de migración
De forma predeterminada, estos cambios solo afectan a las apps que se orientan 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 está orientada a un nivel de API inferior a 26. Es posible que debas actualizar tu app para cumplir con las nuevas limitaciones.
Comprueba el modo en que tu app usa los servicios. Si tu app se basa en 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 destartService()
. - 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 destartService()
. - Busca una forma de duplicar la funcionalidad del servicio con un trabajo programado. Si el servicio no hace algo que el usuario pueda detectar de inmediato, por lo general, deberías poder usar una tarea programada.
- Usa FCM para activar tu aplicación de forma selectiva cuando se producen 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 emisió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 declararlo en el manifiesto. - Usa un trabajo programado para verificar la condición que habría activado la transmisión implícita.