Actualiza el trabajo que ya está en cola

WorkManager te permite actualizar un objeto WorkRequest después de haberlo puesto en cola. A menudo, esto es necesario en apps más grandes que cambian con frecuencia las restricciones o necesitan actualizar sus trabajadores sobre la marcha. A partir de la versión 2.8.0 de WorkManager, la API de updateWork() es el medio para hacerlo.

El método updateWork() te permite cambiar ciertos aspectos de un WorkRequest sobre la marcha, sin tener que realizar el proceso de cancelar y poner en cola uno nuevo de forma manual. Esto simplifica mucho el proceso de desarrollo.

Cómo evitar cancelar el trabajo

Por lo general, debes evitar cancelar una WorkRequest existente y colocar una nueva en la cola. Si lo haces, es posible que la app repita ciertas tareas y podría requerir que escribas una cantidad significativa de código adicional.

Considera los siguientes ejemplos en los que cancelar una WorkRequest puede causar dificultades:

  • Solicitud de backend: Si cancelas una Worker mientras se procesa una carga útil para enviar al servidor, el Worker nuevo debe volver a empezar y volver a calcular la carga útil potencialmente costosa.
  • Programación: Si cancelas un PeriodicWorkRequest y deseas que el nuevo PeriodicWorkRequest se ejecute en el mismo programa, debes calcular una compensación de tiempo para asegurarte de que el nuevo tiempo de ejecución esté alineado con la solicitud de trabajo anterior.

La API de updateWork() te permite actualizar las restricciones de una solicitud de trabajo y otros parámetros sin la molestia de cancelar y poner en cola una solicitud nueva.

Cuándo cancelar un trabajo

Hay casos en los que debes cancelar directamente un WorkRequest en lugar de llamar a updateWork(). Esto es lo que debes hacer cuando quieras cambiar la naturaleza fundamental del trabajo que pusiste en cola.

Cuándo actualizar el trabajo

Imagina una app de fotos que hace una copia de seguridad diaria de las fotos del usuario. Puso en cola un PeriodicWorkRequest para hacerlo. El WorkRequest tiene restricciones que requieren que el dispositivo se esté cargando y esté conectado a Wi-Fi.

Sin embargo, el usuario solo carga su dispositivo durante 20 minutos al día con un cargador rápido. En este caso, es posible que la app quiera actualizar la WorkRequest para disminuir la rigurosidad de la restricción de carga y poder subir las fotos, incluso si el dispositivo no está completamente cargado.

En esta situación, puedes usar el método updateWork() para actualizar las restricciones de la solicitud de trabajo.

Cómo actualizar el trabajo

El método updateWork() proporciona un medio simple para actualizar un WorkRequest existente, sin tener que cancelar y poner en cola uno nuevo.

Para usar el trabajo de actualización en cola, sigue estos pasos:

  1. Obtener el ID existente del trabajo en cola: Obtén el ID de la WorkRequest que deseas actualizar. Puedes recuperar este ID con cualquiera de las APIs de getWorkInfo o si conservas de forma manual el ID de la WorkRequest inicial para recuperarlo más tarde con la propiedad pública WorkRequest.id antes de ponerlo en cola.
  2. Crear una nueva WorkRequest: Crea una WorkRequest nueva y usa WorkRequest.Builder.setID() para establecer su ID de modo que coincida con el de la WorkRequest existente.
  3. Establece restricciones: Usa WorkRequest.Builder.setConstraints() para pasar las nuevas restricciones de WorkManager.
  4. Call updateWork: Pasa la nueva WorkRequest a updateWork().

Ejemplo de actualización de trabajo

A continuación, se muestra un ejemplo de fragmento de código en Kotlin que muestra cómo usar el método updateWork() para cambiar las restricciones de batería de un WorkRequest que se utiliza para subir fotos:

suspend fun updatePhotoUploadWork() {
    // Get instance of WorkManager.
    val workManager = WorkManager.getInstance(context)

    // Retrieve the work request ID. In this example, the work being updated is unique
    // work so we can retrieve the ID using the unique work name.
    val photoUploadWorkInfoList = workManager.getWorkInfosForUniqueWork(
        PHOTO_UPLOAD_WORK_NAME
    ).await()

    val existingWorkRequestId = photoUploadWorkInfoList.firstOrNull()?.id ?: return

    // Update the constraints of the WorkRequest to not require a charging device.
    val newConstraints = Constraints.Builder()
        // Add other constraints as required here.
        .setRequiresCharging(false)
        .build()

    // Create new WorkRequest from existing Worker, new constraints, and the id of the old WorkRequest.
    val updatedWorkRequest: WorkRequest =
        OneTimeWorkRequestBuilder<MyWorker>()
            .setConstraints(newConstraints)
            .setId(existingWorkRequestId)
            .build()

    // Pass the new WorkRequest to updateWork().
    workManager.updateWork(updatedWorkRequest)
}

Controla el resultado

updateWork() muestra un ListenableFuture<UpdateResult>. El UpdateResult determinado puede tener uno de los diversos valores que indican si WorkManager pudo aplicar o no los cambios. También indica cuándo se pudo aplicar el cambio.

Para obtener más información, consulta la referencia updateWork() y UpdateResult.

Haz un seguimiento del trabajo de generaciones

Cada vez que actualizas un WorkRequest, su generación se incrementa en uno. De esta manera, podrás realizar un seguimiento exacto del contenido de WorkRequest que está en cola. Las generaciones te brindan más control cuando observas, rastreas y pruebas las solicitudes de trabajo.

Para obtener la generación de un WorkRequest, sigue estos pasos:

  1. WorkInfo: Llama a WorkManager.getWorkInfoById() para recuperar una instancia de WorkInfo que corresponda a tu WorkRequest.
    • Puedes llamar a uno de varios métodos que muestran un WorkInfo. Para obtener más información, consulta la referencia de WorkManager.
  2. getGeneration: Llama a getGeneration() en la instancia de WorkInfo. La Int que se muestra corresponde a la generación de WorkRequest.
    • Ten en cuenta que no hay un campo de generación o una propiedad, solo el método WorkInfo.getGeneration().

Ejemplo de generación de pistas

La siguiente es una implementación de ejemplo del flujo de trabajo descrito anteriormente para recuperar la generación de un WorkRequest.

// Get instance of WorkManager.
val workManager = WorkManager.getInstance(context)

// Retrieve WorkInfo instance.
val workInfo = workManager.getWorkInfoById(oldWorkRequestId)

// Call getGeneration to retrieve the generation.
val generation = workInfo.getGeneration()

Políticas para actualizar el trabajo

Anteriormente, la solución recomendada para actualizar trabajos periódicos era poner en cola un PeriodicWorkRequest con la política ExistingPeriodicWorkPolicy.REPLACE. Si había un PeriodicWorkRequest pendiente con el mismo id único, la nueva solicitud de trabajo la cancelaría y la borraría. Esta política ahora está obsoleta y se lo reemplazó por el flujo de trabajo que usa ExistingPeriodicWorkPolicy.UPDATE.

Por ejemplo, cuando usas enqueueUniquePeriodicWork con un PeriodicWorkRequest, puedes inicializar el nuevo PeriodicWorkRequest con la política ExistingPeriodicWorkPolicy.UPDATE. Si hay un PeriodicWorkRequest pendiente con el mismo nombre único, WorkManager lo actualiza a la nueva especificación. Si sigues este flujo de trabajo, no es necesario usar updateWork().