Android WorkManager en 2026: Tareas en Segundo Plano, Restricciones y Preguntas de Entrevista

Guía completa sobre WorkManager para Android en 2026: creación de Workers, restricciones de ejecución, encadenamiento de tareas y preguntas técnicas de entrevista.

Android WorkManager architecture diagram showing background task scheduling

WorkManager representa la solución oficial de Jetpack para ejecutar tareas en segundo plano garantizadas en Android. A diferencia de los hilos convencionales o las corrutinas que desaparecen cuando el proceso de la aplicación termina, WorkManager persiste los trabajos programados y los ejecuta incluso después de reiniciar el dispositivo. La versión 2.11.2 (estable, marzo 2026) soporta API 23+ y selecciona automáticamente el mecanismo subyacente óptimo (JobScheduler, AlarmManager) según la versión de Android del dispositivo.

Cuándo usar WorkManager

WorkManager es ideal para tareas diferibles que requieren ejecución garantizada: sincronización de datos, subida de archivos, procesamiento de imágenes. Para operaciones inmediatas sin garantía de supervivencia al proceso, las corrutinas de Kotlin siguen siendo preferibles.

Configuración de WorkManager 2.11 en un Proyecto Kotlin

La integración de WorkManager comienza agregando la dependencia en el archivo Gradle. La versión 2.11+ requiere minSdk 23 y compileSdk 33 como mínimo.

build.gradle.kts (módulo app)gradle
dependencies {
    val workVersion = "2.11.2"
    implementation("androidx.work:work-runtime-ktx:$workVersion")
    // Opcional: para pruebas
    androidTestImplementation("androidx.work:work-testing:$workVersion")
}

El artefacto work-runtime-ktx incluye extensiones de Kotlin y soporte de corrutinas a través de CoroutineWorker. WorkManager se inicializa automáticamente mediante un ContentProvider declarado en el manifiesto de la biblioteca.

Creación de un Worker Simple con doWork()

Una clase Worker hereda de la clase base y sobrescribe el método doWork(). El sistema ejecuta este método en un hilo de segundo plano dedicado.

SyncWorker.ktkotlin
class SyncWorker(
    context: Context,
    params: WorkerParameters
) : Worker(context, params) {

    override fun doWork(): Result {
        // Lectura de datos de entrada
        val userId = inputData.getString("user_id") ?: return Result.failure()
        
        return try {
            // Ejecución de la sincronización
            val syncService = SyncService.getInstance(applicationContext)
            syncService.syncUserData(userId)
            Result.success()
        } catch (e: IOException) {
            // Reintentar en caso de error de red
            Result.retry()
        } catch (e: Exception) {
            // Fallo permanente
            Result.failure()
        }
    }
}

Existen tres resultados posibles: Result.success() indica finalización exitosa, Result.failure() detiene los reintentos, y Result.retry() reprograma según la política de backoff configurada.

Uso de CoroutineWorker para Funciones Suspend

Cuando el trabajo involucra funciones suspend (llamadas Retrofit, consultas Room), CoroutineWorker simplifica considerablemente el código eliminando callbacks anidados.

UploadWorker.ktkotlin
class UploadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        val imageUri = inputData.getString("image_uri")
            ?: return Result.failure()
        
        // Reporte de progreso (visible en observadores de WorkInfo)
        setProgress(workDataOf("status" to "comprimiendo"))
        
        val compressed = ImageCompressor.compress(imageUri)
        
        setProgress(workDataOf("status" to "subiendo"))
        
        return try {
            val api = RetrofitClient.uploadService
            api.uploadImage(compressed)
            Result.success()
        } catch (e: HttpException) {
            if (e.code() in 500..599) Result.retry()
            else Result.failure()
        }
    }
}

El método setProgress() permite comunicar el estado de avance a los observadores de la interfaz de usuario, particularmente útil para operaciones largas como la subida de archivos grandes.

Definición de Restricciones de Ejecución

Las restricciones permiten especificar las condiciones requeridas para la ejecución del trabajo. WorkManager espera hasta que todas las restricciones se cumplan antes de iniciar el Worker.

kotlin
// Restricciones para sincronización de datos
val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)
    .setRequiresBatteryNotLow(true)
    .setRequiresStorageNotLow(true)
    .build()

val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>()
    .setConstraints(constraints)
    .setInputData(workDataOf("user_id" to userId))
    .build()

WorkManager.getInstance(context).enqueue(syncRequest)

Las restricciones disponibles incluyen el tipo de red (CONNECTED, UNMETERED, METERED, NOT_ROAMING), el estado de la batería, el almacenamiento disponible y el estado de carga del dispositivo. En Android 7+, la restricción setRequiresDeviceIdle(true) permite esperar hasta que el dispositivo esté inactivo.

Configuración de Políticas de Backoff

Cuando un Worker retorna Result.retry(), WorkManager reprograma automáticamente la ejecución según una política de backoff configurable.

kotlin
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
    .setBackoffCriteria(
        BackoffPolicy.EXPONENTIAL,
        WorkRequest.MIN_BACKOFF_MILLIS,
        TimeUnit.MILLISECONDS
    )
    .build()

Existen dos políticas disponibles: LINEAR (retraso constante entre intentos) y EXPONENTIAL (retraso que se duplica en cada intento). El retraso mínimo es de 10 segundos, y el máximo alcanza 5 horas.

Encadenamiento de Trabajos Secuenciales y Paralelos

WorkManager permite crear flujos de trabajo complejos encadenando múltiples Workers. Los trabajos pueden ejecutarse secuencial o paralelamente.

kotlin
// Flujo: compresión -> subida -> notificación
val compressWork = OneTimeWorkRequestBuilder<CompressWorker>().build()
val uploadWork = OneTimeWorkRequestBuilder<UploadWorker>().build()
val notifyWork = OneTimeWorkRequestBuilder<NotificationWorker>().build()

WorkManager.getInstance(context)
    .beginWith(compressWork)
    .then(uploadWork)
    .then(notifyWork)
    .enqueue()

Para ejecución paralela, el método beginWith() acepta una lista de WorkRequests:

kotlin
// Descarga paralela de múltiples recursos
val downloads = listOf(
    OneTimeWorkRequestBuilder<DownloadWorker>()
        .setInputData(workDataOf("url" to url1)).build(),
    OneTimeWorkRequestBuilder<DownloadWorker>()
        .setInputData(workDataOf("url" to url2)).build(),
    OneTimeWorkRequestBuilder<DownloadWorker>()
        .setInputData(workDataOf("url" to url3)).build()
)

val mergeWork = OneTimeWorkRequestBuilder<MergeWorker>().build()

WorkManager.getInstance(context)
    .beginWith(downloads)
    .then(mergeWork)
    .enqueue()

Trabajos Únicos y Estrategias de Reemplazo

Los trabajos únicos garantizan que solo exista una instancia de un trabajo particular en la cola, evitando duplicaciones durante llamadas repetidas.

kotlin
val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>().build()

WorkManager.getInstance(context).enqueueUniqueWork(
    "user_sync",
    ExistingWorkPolicy.REPLACE,
    syncRequest
)

Existen tres políticas: REPLACE cancela el trabajo existente y lo reemplaza, KEEP conserva el trabajo existente e ignora el nuevo, APPEND agrega el nuevo trabajo a la cadena existente.

Trabajos Periódicos con PeriodicWorkRequest

Para tareas recurrentes como sincronización de datos o limpieza de caché, PeriodicWorkRequest ofrece programación automática.

kotlin
val periodicSync = PeriodicWorkRequestBuilder<SyncWorker>(
    repeatInterval = 1,
    repeatIntervalTimeUnit = TimeUnit.HOURS,
    flexTimeInterval = 15,
    flexTimeIntervalUnit = TimeUnit.MINUTES
)
    .setConstraints(constraints)
    .build()

WorkManager.getInstance(context).enqueueUniquePeriodicWork(
    "periodic_sync",
    ExistingPeriodicWorkPolicy.UPDATE,
    periodicSync
)

El intervalo mínimo es de 15 minutos. El parámetro flexTimeInterval define una ventana durante la cual el trabajo puede ejecutarse, permitiendo al sistema optimizar el consumo de batería.

Observación del Estado de los Trabajos

La observación de trabajos permite actualizar la interfaz de usuario según el progreso y el resultado.

kotlin
// En un ViewModel
val workInfo: LiveData<WorkInfo> = WorkManager
    .getInstance(application)
    .getWorkInfoByIdLiveData(uploadRequest.id)

// Observación en un Fragment
viewModel.workInfo.observe(viewLifecycleOwner) { info ->
    when (info.state) {
        WorkInfo.State.RUNNING -> {
            val progress = info.progress.getString("status")
            updateProgressUI(progress)
        }
        WorkInfo.State.SUCCEEDED -> showSuccessUI()
        WorkInfo.State.FAILED -> showErrorUI()
        else -> { /* En espera o cancelado */ }
    }
}

¿Listo para aprobar tus entrevistas de Android?

Practica con nuestros simuladores interactivos, flashcards y tests técnicos.

Preguntas de Entrevista Técnica sobre WorkManager

Las entrevistas técnicas de Android frecuentemente abordan WorkManager. A continuación se presentan las preguntas más comunes con sus respuestas detalladas.

¿Cuál es la diferencia entre Worker y CoroutineWorker?

Worker ejecuta doWork() en un hilo de segundo plano de manera síncrona. CoroutineWorker permite utilizar funciones suspend y se ejecuta por defecto en Dispatchers.Default. Para operaciones asíncronas que involucran llamadas de red o accesos a base de datos con Room, CoroutineWorker es preferible.

¿Cómo garantiza WorkManager la ejecución de los trabajos?

WorkManager persiste la información de trabajo en una base de datos SQLite interna. Al iniciar la aplicación o durante el arranque del dispositivo (si el permiso RECEIVE_BOOT_COMPLETED está concedido), WorkManager restaura los trabajos pendientes y los reprograma.

¿Cuál es la duración máxima de ejecución de un Worker?

Un Worker dispone de 10 minutos máximo para completar su trabajo en la mayoría de los dispositivos. Este tiempo puede variar según los fabricantes y las optimizaciones de batería. Para trabajos largos, se debe utilizar setForeground() con una notificación de primer plano.

¿Cómo transmitir datos entre Workers encadenados?

El Worker que termina puede retornar datos mediante Result.success(outputData). El siguiente Worker en la cadena accede a estos datos a través de inputData. Para cadenas paralelas que fusionan hacia un solo Worker, un InputMerger combina las salidas.

kotlin
override fun doWork(): Result {
    val processedId = processData()
    val output = workDataOf("processed_id" to processedId)
    return Result.success(output)
}

¿Cómo probar un Worker?

La biblioteca work-testing proporciona TestListenableWorkerBuilder para pruebas unitarias y WorkManagerTestInitHelper para pruebas de integración.

kotlin
@Test
fun testSyncWorker() = runTest {
    val context = ApplicationProvider.getApplicationContext<Context>()
    val worker = TestListenableWorkerBuilder<SyncWorker>(context)
        .setInputData(workDataOf("user_id" to "123"))
        .build()
    
    val result = worker.doWork()
    
    assertThat(result).isEqualTo(ListenableWorker.Result.success())
}

Conclusión

WorkManager constituye la piedra angular de la gestión de tareas en segundo plano en Android moderno. Su capacidad para persistir trabajos, respetar restricciones del sistema y adaptarse a diferentes versiones de Android lo convierte en una herramienta indispensable. El dominio de los conceptos de restricciones, encadenamiento y políticas de backoff permite construir aplicaciones robustas capaces de manejar eficientemente operaciones asíncronas complejas, incluso en condiciones de red o energía desfavorables.

Reto diario

¿Sabrías detectar el bug en Android?

Un fragmento real, un bug oculto, un intento al día. Sin cuenta para probar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador de SharpSkill

Desarrollador fullstack desde hace más de 10 años. Dirige SharpSkill y responde por todo lo que se publica aquí.

Actualizado el 22 de agosto de 2026

Etiquetas

#android
#workmanager
#kotlin
#jetpack
#background-tasks

Compartir

Artículos relacionados