El framework Cactus proporciona un conjunto robusto de técnicas para mantener aplicaciones Android activas en segundo plano. Integra servicios en primer plano de doble proceso, JobScheduler, la técnica de un píxel, WorkManager y audio silencioso para abordar este desafío. Este artículo se centra en desglosar la estrategia de cooperación entre JobScheduler y WorkManager, dos componentes centrales en la arquitectura de Cactus.
La necesidad de una estrategia de cooperación
El sistema operativo Android tiende a finalizar procesos en segundo plano para conservar recursos. Para garantizar una operación prolongada, Cactus emplea una estrategia de múltiples capas. JobScheduler, introducido en Android 5.0, permite programar tareas basadas en condiciones del sistema. WorkManager, parte de Jetpack, ofrece una API compatible y persistente para tareas diferidas, independientemente de la versión de Android. Su cooperación en Cactus crea redundancia: si una vía es restringida por el sistema (como en modo de bajo consumo), la otra puede continuar ejecutando las tareas esenciales de keep-alive.
Implementación del JobScheduler
Dentro de Cactus, la clase CactusJobService encapsula la lógica de programación. Esta clase gestiona la creación y cancelación de trabajos del sistema. La programación inicializa el servicio y construye una solicitud de trabajo con parámetros específicos.
// Inicialización del programador de trabajos del sistema
val taskScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
val jobIdentifier = 1001
// Configuración de los criterios de ejecución
val jobRequest = JobInfo.Builder(jobIdentifier, ComponentName(context, CactusJobService::class.java))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setRequiresCharging(true)
.setPeriodic(900_000L) // 15 minutos
.build()
// Ejecución de la programación
taskScheduler.schedule(jobRequest)
Para cancelar un trabajo programado, se invoca el método cancel con el identificador correspondiente.
// Anulación de un trabajo programado
taskScheduler.cancel(jobIdentifier)
Utilización de WorkManager
La integración de WorkManager se gestiona mediante funciones de extensión en Kotlin. Estas funciones facilitan el registro y la cancelación de tareas periódicas garantizadas. La política REPLACE asegura que solo exista una instancia de la tarea.
// Definición de la solicitud de trabajo periódico
fun buildKeepAliveWork(): PeriodicWorkRequest {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
return PeriodicWorkRequestBuilder<KeepAliveWorker>(15, TimeUnit.MINUTES)
.setConstraints(constraints)
.addTag("keep_alive_cycle")
.build()
}
// Encolado único de la tarea periódica
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"persistent_keep_alive_job",
ExistingPeriodicWorkPolicy.REPLACE,
buildKeepAliveWork()
)
La cancelación de una tarea específica se realiza utilizando su nombre único.
// Cancelación de la tarea periódica específica
WorkManager.getInstance(context).cancelUniqueWork("persistent_keep_alive_job")
El framework permite configurar el uso de WorkManager mediante un flag booleano, ofreciendo flexibilidad al desarrollador.
// Control de habilitación de WorkManager
var workManagerEnabled: Boolean = true // Habilitado por defecto
Patrón de cooperación y capas adicionales
La cooperación no es simplemente usar ambos sistemas en paralelo, sino diseñar su activación y monitoreo de forma sinérgica. Durante la inicialización de Cactus, tanto el JobService como la tarea de WorkManager se registran. Cada uno actúa como un respaldo para el otro. Si el sistema limita el JobScheduler (por ejemplo, en modo Doze agresivo), WorkManager sigue operando, y viceversa. Esta arquitectura se complementa con otras técnicas de Cactus: los servicios en primer plano de doveles procesos proporcionan una presencia visible al sistema, la técnica de un píxel crea una actviidad mínima que evita la congelación del proceso, y el audio silencioso mantiene el foco de audio del sistema. Esta combinación de técnicas forman un sistema de defensa en profundidad contra la terminación de procesos.