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, elWorker
nuevo debe volver a empezar y volver a calcular la carga útil potencialmente costosa. - Programación: Si cancelas un
PeriodicWorkRequest
y deseas que el nuevoPeriodicWorkRequest
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:
- 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úblicaWorkRequest.id
antes de ponerlo en cola. - Crear una nueva WorkRequest: Crea una
WorkRequest
nueva y usaWorkRequest.Builder.setID()
para establecer su ID de modo que coincida con el de laWorkRequest
existente. - Establece restricciones: Usa
WorkRequest.Builder.setConstraints()
para pasar las nuevas restricciones de WorkManager. - 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:
- WorkInfo: Llama a
WorkManager.getWorkInfoById()
para recuperar una instancia deWorkInfo
que corresponda a tuWorkRequest
.- Puedes llamar a uno de varios métodos que muestran un
WorkInfo
. Para obtener más información, consulta la referencia de WorkManager.
- Puedes llamar a uno de varios métodos que muestran un
- getGeneration: Llama a
getGeneration()
en la instancia deWorkInfo
. LaInt
que se muestra corresponde a la generación deWorkRequest
.- Ten en cuenta que no hay un campo de generación o una propiedad, solo el método
WorkInfo.getGeneration()
.
- Ten en cuenta que no hay un campo de generación o una propiedad, solo el método
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()
.