Aggiornare il lavoro già accodato

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 nuovo Worker deve ricominciare da capo e ricalcolare il payload potenzialmente costoso.
  • Programmazione: se annulli una PeriodicWorkRequest e vuoi che il nuovo PeriodicWorkRequest 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:

  1. 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à pubblica WorkRequest.id, prima di accodarla.
  2. Crea una nuova richiesta di lavoro: crea una nuova risorsa WorkRequest e utilizza WorkRequest.Builder.setID() per impostare il relativo ID in modo che corrisponda a quello dell'elemento WorkRequest esistente.
  3. Impostazione di vincoli: utilizza WorkRequest.Builder.setConstraints() per superare i nuovi vincoli di WorkManager.
  4. 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:

  1. WorkInfo: chiama WorkManager.getWorkInfoById() per recuperare un'istanza di WorkInfo corrispondente al tuo WorkRequest.
  2. getGeneration: chiama getGeneration() sull'istanza di WorkInfo. Il valore Int restituito corrisponde alla generazione del WorkRequest.
    • Tieni presente che non esiste una proprietà o un campo di generazione, ma solo il metodo WorkInfo.getGeneration().

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().