Cada vez que una app se ejecuta en segundo plano, consume alguno de los recursos limitados del dispositivo, como la memoria RAM. Esto puede afectar la experiencia del usuario, en especial si este usa una app que requiere una gran cantidad de recursos, como un juego o un reproductor de video. Para mejorar la experiencia del usuario, Android 8.0 (nivel de API 26) impone limitaciones en las capacidades de las apps mientras se ejecutan en segundo plano. En este documento, se describen los cambios en el sistema operativo y el modo en que puedes actualizar tu app para que funcione correctamente con las nuevas limitaciones.
Descripción general
Muchas app y servicios de Android se pueden ejecutar de manera simultánea. Por ejemplo, un usuario puede abrir un juego en una ventana mientras navega por la Web en otra , y recurrir a una tercera app para reproducir música. Cuantas más apps se ejecuten a la vez, mayor será la carga para el sistema. Si se ejecutan más apps o servicios en segundo plano, aumenta la carga del sistema, lo que puede generar una mala experiencia del usuario (por ejemplo, la app de música podría cerrarse de forma inesperada).
Para disminuir las posibilidades 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 de servicios en segundo plano: Mientras una app está inhabilitada, existen límites para su uso de servicios en segundo plano. Esto no se aplica a servicios en primer plano, que son más notorios para el usuario.
Limitaciones de transmisión: A excepción de algunos casos limitados, las apps no pueden usar sus manifiestos para registrarse en transmisiones implícitas. Sin embargo, pueden registrarse en estas transmisiones durante el tiempo de ejecución y usar los manifiestos a fin de registrarse en transmisiones explícitas destinadas específicamente a ellas.
En la mayoría de los casos, las apps pueden resolver estas limitaciones usando trabajos JobScheduler
. Este enfoque permite que un arreglo de apps realice
tareas cuando no se esté ejecutando de forma activa; sin embargo, le da al sistema
la libertad de programar esas tareas de una forma que no afecte la experiencia del
usuario. Android 8.0 ofrece varias mejoras a JobScheduler
que facilitan el reemplazo de receptores de
transmisión y servicios que tienen trabajos programados. Para obtener más información, consulta
Mejoras de JobScheduler.
Limitaciones de servicios en segundo plano
Los servicios que se ejecutan en segundo plano pueden consumir recursos del dispositivo, lo que puede empeorar la experiencia del usuario. Para mitigar este problema, el sistema aplica varias limitaciones a los servicios.
El sistema distingue entre apps en primer y segundo plano. (La definición de segundo plano para las limitaciones de servicio es diferente de la definición que usa la administración de memoria; una app puede estar en segundo plano cuando corresponde a la administración de memoria y en primer plano cuando corresponde a su capacidad para el lanzamiento de servicios). Se considera que una aplicación se encuentra en primer plano si alguna de las siguientes consideraciones es verdadera:
- Tiene una actividad visible, independientemente de que la actividad esté iniciada o pausada.
- Tiene un servicio en primer plano.
- Otra app en primer plano está conectada con la app, ya sea mediante un enlace con uno
de sus servicios o el uso de uno de sus proveedores de contenido. Por ejemplo,
la aplicación se encuentra en primer plano si otra se enlaza a su:
- IME
- Servicio de fondo de pantalla
- Receptor de notificación
- Servicio de voz o texto
Si ninguna de esas condiciones es verdadera, se considera que la app se encuentra en segundo plano.
Nota: Estas reglas no afectan a los servicios enlazados de ningún modo. Si tu app define un servicio enlazado, se pueden enlazar otros componentes a ese servicio independientemente de que tu app esté o no en primer 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 funcionar en segundo plano, tiene una
ventana de varios minutos durante los cuales puede, de todos modos, 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
hubiese llamado a los métodos Service.stopSelf()
de los servicios.
En determinadas circunstancias, una app en segundo plano se ubica en una lista blanca temporal durante varios minutos. Mientras se encuentre en la lista blanca, una app podrá lanzar servicios sin limitaciones y se permitirá la ejecución de los que estén en segundo plano. Una app se ubica en la lista blanca cuando administra una tarea que es visible para el usuario. Por ejemplo:
- Administrar un mensaje de Firebase Cloud Messaging (FCM) de prioridad alta
- Recibir una transmisión (por ejemplo, SMS y MMS)
- Ejecutar un elemento
PendingIntent
desde una notificación - Iniciar un objeto
VpnService
antes de que la app de VPN se promocione en primer plano.
Nota:
IntentService
es un servicio y, por lo tanto, está sujeto a
las nuevas restricciones sobre servicios en segundo plano. Como resultado, muchas apps que dependen de
IntentService
no funcionan correctamente cuando se dirigen a Android
8.0 o versiones posteriores. Por este
motivo, la Biblioteca de compatibilidad
de Android 26.0.0 introduce una nueva clase
JobIntentService
, que ofrece la misma funcionalidad
que IntentService
, pero usa trabajos en lugar de
servicios cuando se ejecuta en Android 8.0 o versiones posteriores.
En muchos casos, tu app puede reemplazar servicios en segundo plano por trabajos JobScheduler
. Por ejemplo, CoolPhotoApp debe verificar
si el usuario ha recibido fotos compartidas de amigos, incluso si la app no se
ejecuta en primer plano. Anteriormente, la app usaba un servicio en segundo plano que
se activaba con el almacenamiento en la nube de la app. Para realizar la migración a Android 8.0 (nivel de API 26),
el desarrollador reemplaza el servicio en segundo plano por un trabajo programado, que se
lanza 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
consistía en crear un servicio en segundo plano y luego hacer que pasara 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 ese plano. Por esta razón, en Androidִ 8.0 se presenta
el nuevo método startForegroundService()
para iniciar un servicio nuevo en
primer plano. Una vez que el sistema crea
el servicio, la app tiene cinco segundos para llamar al método startForeground()
de ese servicio a fin de mostrar la notificación visible para el usuario
del nuevo servicio. Si la app no llama a startForeground()
en ese
plazo, el sistema detiene el servicio y declara un estado
ANR para esta.
Limitaciones de transmisión
Si una app se registra para recibir transmisiones, el receptor de esta consume recursos cada vez que se realiza una transmisión. Esto puede causar problemas si demasiadas apps se registran para recibir transmisiones según los eventos del sistema; un evento del sistema que activa una transmisión puede hacer que todas las apps consuman recursos de manera rápida y sucesiva, lo cual puede afectar la experiencia del usuario. Para mitigar este problema, Android 7.0 (nivel de API 24) impuso limitaciones sobre 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 aplicaciones dirigidas a Android 8.0 o versiones posteriores ya no pueden registrar
receptores para
transmisiones implícitas en su manifiesto. Una transmisión implícita es una transmisión
que no está dirigida a esa app específicamente. Por ejemplo,
ACTION_PACKAGE_REPLACED
es una transmisión implícita, ya que se envía a todos los receptores registrados, y comunica a estos que se reemplazó algún paquete en el dispositivo. Sin embargo,ACTION_MY_PACKAGE_REPLACED
no es una transmisión implícita, ya que se envía solo a la app cuyo paquete se reemplazó, sin importar cuántas otras apps hayan registrado receptores para esa transmisión. - 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 se excluyen de la 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 usando un trabajo JobScheduler
.
Por ejemplo, es posible que una app social de fotografía deba realizar una limpieza en sus datos
de vez en cuando y priorice 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
realizar la migración a Android 8.0 o versiones posteriores, la app quita el receptor de su
manifiesto. En cambio, 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 dirigidas a Android 8.0 (nivel de API 26) o versiones posteriores. Sin embargo, los usuarios pueden habilitar la mayoría de estas restricciones para cualquier app desde la pantalla Configuración, incluso si la app está dirigida a una API de nivel 26 o versiones anteriores. Es posible que debas actualizar tu app para que cumpla con las limitaciones nuevas.
Comprueba el modo en que tu app usa los servicios. Si tu app usa servicios que se ejecutan en segundo plano mientras se encuentra inactiva, deberás reemplazarlos. Entre las posibles soluciones, se incluyen las siguientes:
- Si tu app debe crear un servicio en primer plano mientras funciona
en segundo plano, usa el método nuevo
startForegroundService()
en lugar destartService()
. - Si el servicio es visible para el usuario, conviértelo en un servicio en segundo plano. Por
ejemplo, un servicio que reproduce audio debe ser siempre de primer plano.
Crea el servicio con el método
startForegroundService()
en lugar destartService()
. - Encuentra una manera de duplicar la funcionalidad del servicio con un trabajo programado. Si el servicio no realiza ninguna acción que el usuario note al instante, por lo general, puedes usar un trabajo programado.
- En lugar de realizar sondeos en segundo plano, usa FCM para activar tu aplicación de manera selectiva cuando se produzcan eventos de red.
- Difiere tareas en segundo plano hasta que la aplicación se encuentre naturalmente en primer plano.
Revisa los receptores de transmisiones definidos en el manifiesto de tu app. Si tu manifiesto establece un receptor para una transmisión implícita, debes reemplazarlo. Entre las posibles soluciones, se incluyen las siguientes:
- Crear el receptor durante el tiempo de ejecución llamando a
Context.registerReceiver()
, en lugar de declarar el receptor en el manifiesto - Usar un trabajo programado para buscar la condición que haya activado la transmisión implícita