WorkManager consente di aggiornare una WorkRequest
dopo averla già messa in coda. Questa operazione è spesso necessaria nelle app di grandi dimensioni che cambiano spesso i vincoli o devono aggiornare i worker al volo. A partire dalla versione 2.8.0 di WorkManager, per farlo è disponibile l'API updateWork()
.
Il metodo updateWork()
ti consente di modificare al volo determinati aspetti di una WorkRequest
, senza dover svolgere la procedura di annullamento manuale e accodamento di uno nuovo. Questo semplifica notevolmente il
processo di sviluppo.
Evita di annullare il lavoro
In genere, conviene evitare di annullare una richiesta di lavoro esistente e di accodarne una nuova. In questo modo, l'app potrebbe ripetere determinate attività e richiedere la scrittura di una quantità significativa di codice aggiuntivo.
Considera i seguenti esempi di casi in cui l'annullamento di una richiesta di lavoro può causare difficoltà:
- Richiesta di backend: se annulli una
Worker
mentre sta elaborando un payload da inviare al server, il nuovoWorker
deve ricominciare da capo e ricalcolare il payload potenzialmente costoso. - Programmazione: se annulli una
PeriodicWorkRequest
e vuoi che il nuovoPeriodicWorkRequest
venga eseguito con la stessa pianificazione, devi calcolare uno scarto temporale per assicurarti che il nuovo tempo di esecuzione sia in linea con la richiesta di lavoro precedente.
L'API updateWork()
consente di aggiornare i vincoli e altri parametri di una richiesta di lavoro senza il problema di annullare e accodare una nuova richiesta.
Quando annullare il lavoro
In alcuni casi devi annullare direttamente un WorkRequest
anziché chiamare updateWork()
. È la prima cosa che devi fare quando vuoi
modificare la natura fondamentale dell'opera che hai messo in coda.
Quando aggiornare il lavoro
Immagina un'app per le foto che esegue il backup giornaliero delle foto dell'utente. Ha
accodato un PeriodicWorkRequest
per farlo. Il WorkRequest
ha limitazioni
che richiedono che il dispositivo sia in carica e connesso alla rete Wi-Fi.
Tuttavia, l'utente ricarica il dispositivo solo per 20 minuti al giorno utilizzando un caricabatterie rapido. In questo caso, l'app può aggiornare WorkRequest
per allentare il vincolo di ricarica, in modo che possa comunque caricare le foto anche se il dispositivo non è completamente carico.
In questo caso, puoi utilizzare il metodo updateWork()
per aggiornare i vincoli della richiesta di lavoro.
Come aggiornare il lavoro
Il metodo updateWork()
consente di aggiornare facilmente un elemento WorkRequest
esistente, senza dover annullare e accodare un nuovo elemento.
Per utilizzare il lavoro aggiornato in coda, procedi nel seguente modo:
- Recupera l'ID esistente per il lavoro accodato: ottieni l'ID della richiesta di lavoro da aggiornare. Puoi recuperare questo ID con una qualsiasi delle
API
getWorkInfo
oppure ripristinando manualmente l'ID dalla risorsa WorkRequest iniziale per il recupero successivo con la proprietà pubblicaWorkRequest.id
, prima di accodarla. - Crea una nuova richiesta di lavoro: crea una nuova risorsa
WorkRequest
e utilizzaWorkRequest.Builder.setID()
per impostare il relativo ID in modo che corrisponda a quello dell'elementoWorkRequest
esistente. - Impostazione di vincoli: utilizza
WorkRequest.Builder.setConstraints()
per superare i nuovi vincoli di WorkManager. - Call updateWork: trasmetti la nuova richiesta di lavoro a
updateWork()
.
Esempio di aggiornamento del lavoro
Ecco uno snippet di codice di esempio in Kotlin che mostra come utilizzare il metodo updateWork()
per modificare i vincoli della batteria di un WorkRequest
utilizzato per caricare le foto:
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)
}
Gestire il risultato
updateWork()
restituisce un ListenableFuture<UpdateResult>
. L'elemento
UpdateResult
specificato può avere uno dei vari valori che indicano se
WorkManager è stato in grado di applicare le modifiche. Indica anche quando è riuscita
ad applicare la modifica.
Per saperne di più, consulta il updateWork()
e UpdateResult
riferimento.
Monitora il lavoro con generazioni
Ogni volta che aggiorni un WorkRequest
, la relativa generazione viene incrementata di uno. Ciò
ti consente di monitorare esattamente quale WorkRequest
è attualmente accodato.
Le generazioni ti offrono un maggiore controllo durante l'osservazione, il tracciamento e i test delle richieste di lavoro.
Per ottenere la generazione di un WorkRequest
, segui questi passaggi:
- WorkInfo: chiama
WorkManager.getWorkInfoById()
per recuperare un'istanza diWorkInfo
corrispondente al tuoWorkRequest
.- Puoi chiamare uno dei vari metodi che restituiscono
WorkInfo
. Per ulteriori informazioni, consulta la documentazione di riferimento su WorkManager.
- Puoi chiamare uno dei vari metodi che restituiscono
- getGeneration: chiama
getGeneration()
sull'istanza diWorkInfo
. Il valoreInt
restituito corrisponde alla generazione delWorkRequest
.- Tieni presente che non esiste una proprietà o un campo di generazione, ma solo il metodo
WorkInfo.getGeneration()
.
- Tieni presente che non esiste una proprietà o un campo di generazione, ma solo il metodo
Esempio di generazione di percorsi
Di seguito è riportato un esempio di implementazione del flusso di lavoro descritto in precedenza per recuperare la generazione di un elemento 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()
Norme per l'aggiornamento del lavoro
In precedenza, la soluzione consigliata per l'aggiornamento del lavoro periodico era accodare un
PeriodicWorkRequest
con il criterio ExistingPeriodicWorkPolicy.REPLACE
.
Se era presente una PeriodicWorkRequest
in attesa con lo stesso id
univoco, la nuova richiesta di lavoro verrà annullata ed eliminata. Questo criterio è ora ritirato a favore del flusso di lavoro che utilizza il ExistingPeriodicWorkPolicy.UPDATE
.
Ad esempio, quando utilizzi enqueueUniquePeriodicWork
con un
PeriodicWorkRequest
, puoi inizializzare il nuovo PeriodicWorkRequest
con il
criterio ExistingPeriodicWorkPolicy.UPDATE
. Se è presente una PeriodicWorkRequest
in attesa con lo stesso nome univoco, WorkManager lo aggiorna alla nuova specifica. Seguendo questo flusso di lavoro, non è necessario utilizzare
updateWork()
.