Definisci le richieste di lavoro

La guida introduttiva spiegava come creare una semplice WorkRequest e lo accoda.

In questa guida imparerai a definire e personalizzare gli oggetti WorkRequest per gestire casi d'uso comuni, ad esempio come:

  • Pianifica il lavoro una tantum e ricorrente
  • Imposta limiti di lavoro, ad esempio la necessità di utilizzare una rete Wi-Fi o di ricaricare la batteria
  • Garantire un ritardo minimo nell'esecuzione del lavoro
  • Impostazione di strategie di ripetizione e backoff
  • Trasmetti i dati di input al lavoro
  • Raggruppa le attività correlate utilizzando i tag

Panoramica

Il lavoro viene definito in WorkManager tramite un WorkRequest. Per per pianificare qualsiasi lavoro con WorkManager, devi prima creare WorkRequest e poi lo accoda.

Kotlin

val myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest)

Java

WorkRequest myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest);

L'oggetto WorkRequest contiene tutte le informazioni necessarie a WorkManager per di pianificare ed eseguire il lavoro. Include i vincoli che devono essere soddisfatti lavorare per eseguire, pianificare informazioni come ritardi o intervalli ripetuti, riprovare configurazione e potrebbe includere dati di input, se il tuo lavoro si basa su questi dati.

WorkRequest stesso è una classe base astratta. Esistono due metodi le implementazioni derivate di questa classe, che puoi usare per creare la richiesta, OneTimeWorkRequest e PeriodicWorkRequest. Come implicano il loro nome, OneTimeWorkRequest è utile per la programmazione lavori non ripetitivi, mentre PeriodicWorkRequest è più appropriato per il lavoro di pianificazione che si ripete a un certo intervallo.

Pianificare il lavoro una tantum

Per le attività semplici, che non richiedono alcuna configurazione aggiuntiva, utilizza il metodo from:

Kotlin

val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)

Java

WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);

Per operazioni più complesse, puoi utilizzare uno strumento di creazione:

Kotlin

val uploadWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilder<MyWork>()
       // Additional configuration
       .build()

Java

WorkRequest uploadWorkRequest =
   new OneTimeWorkRequest.Builder(MyWork.class)
       // Additional configuration
       .build();

Pianifica tempi di lavoro più rapidi

WorkManager 2.7.0 ha introdotto il concetto di lavoro accelerato. Ciò consente WorkManager consente di eseguire lavori importanti dando al sistema un migliore controllo. rispetto all'accesso alle risorse.

Il lavoro accelerato si distingue per le seguenti caratteristiche:

  • Importanza: il lavoro accelerato è adatta ad attività importanti per l'utente o sono avviati dall'utente.
  • Velocità: il lavoro accelerato è ideale per attività brevi che iniziano immediatamente e verrà completata in pochi minuti.
  • Quote: una quota a livello di sistema che limita il tempo di esecuzione in primo piano determina se un job accelerato può essere avviato.
  • Gestione alimentazione: limitazioni relative alla gestione dell'alimentazione, ad esempio batteria. Le funzionalità di risparmio e Sospensione hanno meno probabilità di incidere sul lavoro accelerato.
  • Latenza: il sistema esegue immediatamente il lavoro accelerato, a condizione che carico di lavoro attuale del sistema consente di farlo. Ciò significa che sono latenti sensibili e non può essere pianificata per l'esecuzione successiva.

Un potenziale caso d'uso per velocizzare il lavoro potrebbe essere all'interno di un'app di chat quando l'utente vuole inviare un messaggio o un'immagine allegata. Analogamente, un'app che gestisce una di pagamento o di abbonamento può anche voler usare la modalità di lavoro accelerato. Questo è perché queste attività sono importanti per l'utente, vengono eseguite rapidamente in background, devono iniziare immediatamente e devono continuare a essere eseguiti anche l'utente chiude l'app

Quote

Il sistema deve allocare il tempo di esecuzione a un job accelerato prima che avvenga possono essere eseguiti. Il tempo di esecuzione non è illimitato. Piuttosto, ogni app riceve una quota in termini di tempo di esecuzione. Quando l'app utilizza il tempo di esecuzione e raggiunge la quota allocata, non puoi più eseguire il lavoro accelerato fino al raggiungimento della quota vengono aggiornate. Ciò consente ad Android di bilanciare più efficacemente le risorse tra diverse applicazioni.

Il tempo di esecuzione disponibile per un'app si basa sul bucket standby e l'importanza del processo.

Puoi determinare cosa accade quando la quota di esecuzione non consente velocizzando l'esecuzione immediata del job. Per informazioni dettagliate, consulta gli snippet di seguito.

Esecuzione accelerata del lavoro

A partire da WorkManager 2.7, la tua app può chiamare setExpedited() per dichiarare che un WorkRequest dovrebbe essere eseguito il più rapidamente possibile utilizzando un job accelerato. La Il seguente snippet di codice fornisce un esempio di utilizzo di setExpedited():

Kotlin

val request = OneTimeWorkRequestBuilder<SyncWorker>()
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build()

WorkManager.getInstance(context)
    .enqueue(request)

Java

OneTimeWorkRequest request = new OneTimeWorkRequestBuilder<T>()
    .setInputData(inputData)
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build();

In questo esempio, inizializziamo un'istanza di OneTimeWorkRequest e chiamiamo setExpedited(). Questa richiesta diventa quindi un lavoro più rapido. Se la quota l'esecuzione in background lo consente. Se la quota è , il parametro OutOfQuotaPolicy indica che la richiesta deve di essere eseguito normalmente e non accelerato.

Compatibilità con le versioni precedenti e servizi in primo piano

Per mantenere la compatibilità con le versioni precedenti per i job più rapidi, WorkManager potrebbe eseguire un servizio in primo piano su versioni della piattaforma precedenti ad Android 12. I servizi in primo piano possono mostrare una notifica all'utente.

I metodi getForegroundInfoAsync() e getForegroundInfo() nel tuo Worker Consenti a WorkManager di visualizzare una notifica quando chiami setExpedited() versioni precedenti ad Android 12.

Qualsiasi ListenableWorker deve implementare il metodo getForegroundInfo se vuole richiedere che l'attività venga eseguita come job accelerato.

Quando scegli come target Android 12 o versioni successive, i servizi in primo piano rimangono disponibili per mediante il metodo setForeground corrispondente.

Lavoratore

I lavoratori non sanno se il lavoro che svolgono è accelerato o meno. Ma i lavoratori possono visualizzare una notifica su alcune versioni di Android Hai velocizzato WorkRequest.

Per attivare questa funzionalità, WorkManager fornisce il metodo getForegroundInfoAsync(), che è necessario implementare per consentire a WorkManager di visualizzare una notifica per avviare ForegroundService se necessario.

Coroutine

Se utilizzi un CoroutineWorker, devi implementare getForegroundInfo(). Poi passalo a setForeground() in doWork(). In questo modo si crea nelle versioni di Android precedenti alla 12.

Considera il seguente esempio:

  class ExpeditedWorker(appContext: Context, workerParams: WorkerParameters):
   CoroutineWorker(appContext, workerParams) {

   override suspend fun getForegroundInfo(): ForegroundInfo {
       return ForegroundInfo(
           NOTIFICATION_ID, createNotification()
       )
   }

   override suspend fun doWork(): Result {
       TODO()
   }

    private fun createNotification() : Notification {
       TODO()
    }

}

Criteri per le quote

Puoi controllare cosa succede al lavoro accelerato quando l'app raggiunge la quota di esecuzione. Per continuare, puoi superare setExpedited():

  • OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST, che fa sì che il job come una normale richiesta di lavoro. Lo snippet riportato sopra dimostra questo.
  • OutOfQuotaPolicy.DROP_WORK_REQUEST, che determina l'annullamento della richiesta se non è sufficiente.

App di esempio

Per un esempio completo di come WorkManager 2.7.0 utilizza il lavoro accelerato, guarda tramite WorkManagerSample su GitHub.

Lavoro accelerato differito

Il sistema tenta di eseguire un determinato job accelerato il prima possibile dopo un job viene richiamato. Tuttavia, come nel caso di altri tipi di job, il sistema potrebbe posticipare l'inizio di nuovo lavoro accelerato, come nei seguenti casi:

  • Caricamento: il carico del sistema è troppo elevato, che può verificarsi quando vengono eseguiti troppi job è già in esecuzione o quando il sistema non dispone di memoria sufficiente.
  • Quota: il limite di quota accelerata dei job è stato superato. Lavoro accelerato utilizza un sistema di quote basato sui bucket di standby delle app e limita il tempo massimo di esecuzione in un intervallo di tempo di rotazione. Le quote utilizzate le attività accelerate sono più restrittive di quelle usate per altri tipi di job in background.

Programma il lavoro periodico

A volte, la tua app potrebbe richiedere l'esecuzione periodica di determinate operazioni. Ad esempio: ti consigliamo di eseguire periodicamente il backup dei tuoi dati, scaricare nuovi contenuti nel tuo o caricare i log su un server.

Ecco come utilizzare PeriodicWorkRequest per creare un Oggetto WorkRequest che viene eseguito periodicamente:

Kotlin

val saveRequest =
       PeriodicWorkRequestBuilderS<aveImageToFileWorker(>1, TimeUnit.HOURS)
    // Additional configuration
           .build()

Java

PeriodicWorkRequest saveRequest =
       new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS)
           // Constraints
           .build();

In questo esempio, il lavoro è pianificato con un intervallo di un'ora.

Il periodo di intervallo è definito come il tempo minimo tra le ripetizioni. La il momento esatto in cui verrà eseguito il worker dipende dai vincoli che stai utilizzando nell'oggetto WorkRequest e nelle ottimizzazioni eseguite dal sistema.

Intervalli di esecuzione flessibili

Se la natura del tuo lavoro lo rende sensibile alle tempistiche di esecuzione, puoi configurare il tuo PeriodicWorkRequest per correre entro un flex periodo all'interno di ciascun periodo di intervallo, come mostrato nella Figura 1.

Puoi impostare un intervallo di flessibilità per un job periodico. Definisci un intervallo di ripetizione,
e un intervallo di flessibilità che specifica una certa quantità di tempo alla fine
di ripetizione. WorkManager tenta di eseguire il job in un determinato momento durante
di flessione in ogni ciclo.

Figura 1. Il diagramma mostra gli intervalli ripetuti con il punto flessibile in che il lavoro può eseguire.

Per definire il lavoro periodico con un periodo flessibile, devi trasmettere flexInterval insieme a repeatInterval durante la creazione di PeriodicWorkRequest. Periodo di flessibilità inizia alle ore repeatInterval - flexInterval e arriva alla fine dell'intervallo.

Di seguito è riportato un esempio di lavoro periodico che può essere eseguito negli ultimi 15 minuti di ogni periodo di un'ora.

Kotlin

val myUploadWork = PeriodicWorkRequestBuilderS<aveImageToFileWorker(>
       1, TimeUnit.HOURS, // repeatInterval (the period cycle)
       15, TimeUnit.MINUTES) // flexInterval
    .build()

Java

WorkRequest saveRequest =
       new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class,
               1, TimeUnit.HOURS,
               15, TimeUnit.MINUTES)
           .build();

L'intervallo di ripetizione deve essere maggiore o uguale a PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS e il flex deve essere maggiore o uguale a PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS.

Effetto dei vincoli sul lavoro periodico

Puoi applicare vincoli al lavoro periodico. Ad esempio, potresti aggiungere alla tua richiesta di lavoro in modo che l'esecuzione del lavoro venga eseguita solo quando Il dispositivo è in carica. In questo caso, anche se passa l'intervallo di ripetizione definito, PeriodicWorkRequest non verrà eseguito finché questa condizione non sarà soddisfatta. Questo potrebbe l'esecuzione di una particolare esecuzione del lavoro viene ritardata o viene ignorata se non vengono soddisfatte durante l'intervallo di esecuzione.

Vincoli di lavoro

I vincoli assicurano che il lavoro venga differito fino a quando non vengono soddisfatte le condizioni ottimali. I seguenti vincoli sono disponibili per WorkManager.

Tipo di rete Vincola il tipo di rete richiesto per l'esecuzione del tuo lavoro. ad esempio Wi-Fi (UNMETERED).
BatteriaNonBassa Se impostato su true, il lavoro non verrà eseguito se il dispositivo è in modalità batteria scarica.
Richiede la ricarica Se impostato su true, il lavoro verrà eseguito soltanto quando il dispositivo è in carica.
Inattività Se impostato su true, richiede che il dispositivo dell'utente rimanga inattivo prima dell'esecuzione del lavoro. Questo può essere utile per eseguire operazioni in batch che potrebbero avere un impatto negativo sulle prestazioni di altre app in esecuzione attiva sul dispositivo dell'utente.
ArchiviazioneNonBassa Se il criterio viene impostato su true, il lavoro non verrà eseguito se lo spazio di archiviazione dell'utente sul dispositivo è troppo basso.

Per creare un insieme di vincoli e associarlo a un determinato lavoro, crea un Constraints utilizzando Contraints.Builder() e assegnarla al tuo WorkRequest.Builder().

Ad esempio, il seguente codice crea una richiesta di lavoro che viene eseguita solo quando il dispositivo dell'utente è in carica e connesso al Wi-Fi:

Kotlin

val constraints = Constraints.Builder()
   .setRequiredNetworkType(NetworkType.UNMETERED)
   .setRequiresCharging(true)
   .build()

val myWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilderM<yWork(>)
       .setConstraints(constraints)
       .build()

Java

Constraints constraints = new Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresCharging(true)
       .build();

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
               .setConstraints(constraints)
               .build();

Quando vengono specificati più vincoli, il lavoro verrà eseguito solo quando vengono soddisfatti i vincoli.

Nel caso in cui un vincolo non venga soddisfatto mentre il lavoro è in esecuzione, WorkManager interromperà il tuo worker. Il lavoro verrà ritentato quando verranno vengono soddisfatti i vincoli.

Lavoro in ritardo

Nel caso in cui il lavoro non abbia vincoli o che tutti i vincoli siano soddisfatta quando il lavoro è in coda, il sistema può scegliere di eseguirlo immediatamente. Se non vuoi che il lavoro venga eseguito immediatamente, puoi specificare il tuo lavoro per iniziare dopo un ritardo iniziale minimo.

Ecco un esempio di come impostare il lavoro in modo che venga eseguito almeno 10 minuti dopo è stato accodato.

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilderM<yWork(>)
   .setInitialDelay(10, TimeUnit.MINUTES)
   .build()

Java

WorkRequest myWorkRequest =
      new OneTimeWorkRequest.Builder(MyWork.class)
               .setInitialDelay(10, TimeUnit.MINUTES)
               .build();

Mentre l'esempio illustra come impostare un ritardo iniziale per un OneTimeWorkRequest, puoi anche impostare un ritardo iniziale per una PeriodicWorkRequest. In questo caso, solo la prima esecuzione del lavoro periodico sarebbero in ritardo.

Criterio di ripetizione e backoff

Se è necessario che WorkManager esegua un nuovo tentativo, puoi restituire Result.retry() dal worker. Il tuo lavoro sarà quindi riprogrammate in base a un ritardo di backoff e a un criterio di backoff.

  • Ritardo backoff specifica il tempo minimo di attesa prima di riprovare il tuo lavoro dopo il primo tentativo. Questo valore non può essere inferiore a 10 secondi (o MIN_BACKOFF_MILLIS).

  • Il criterio di backoff definisce in che modo il ritardo di backoff deve aumentare nel tempo per nuovi tentativi in seguito. WorkManager supporta due criteri di backoff: LINEAR e EXPONENTIAL.

Ogni richiesta di lavoro ha un criterio di backoff e un ritardo nel backoff. Il criterio predefinito è EXPONENTIAL con un ritardo di 30 secondi, ma puoi sostituirlo nelle configurazione delle richieste di lavoro.

Ecco un esempio di personalizzazione del ritardo e del criterio di backoff.

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilderM<yWork(>)
   .setBackoffCriteria(
       BackoffPolicy.LINEAR,
       OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
       TimeUnit.MILLISECONDS)
   .build()

Java

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
               .setBackoffCriteria(
                       BackoffPolicy.LINEAR,
                       OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                       TimeUnit.MILLISECONDS)
               .build();

In questo esempio, il ritardo di backoff minimo è impostato sul valore minimo consentito, per 10 secondi. Poiché il criterio è LINEAR, l'intervallo tra i nuovi tentativi aumenterà di di circa 10 secondi a ogni nuovo tentativo. Ad esempio, la prima esecuzione verrà eseguito un nuovo tentativo dopo 10 secondi per terminare con Result.retry(). seguito da 20, 30, 40 e così via, se il lavoro continua a tornare Result.retry() dopo tentativi successivi. Se il criterio di backoff fosse impostato su EXPONENTIAL, la sequenza della durata dei nuovi tentativi sarà più vicina a 20, 40, 80 e così via attiva.

Tagga lavoro

Ogni richiesta di lavoro ha un identificatore univoco, che può essere utilizzato per identificare che lavorano in un secondo momento per annullare il lavoro o osservarne lo stato di avanzamento.

Se hai un gruppo di lavori logicamente correlati, potrebbe essere utile anche tagga quegli elementi di lavoro. Il tagging ti consente di lavorare con un gruppo di lavoro richieste insieme.

Ad esempio, WorkManager.cancelAllWorkByTag(String) annulla tutte le richieste di lavoro con un determinato tag WorkManager.getWorkInfosByTag(String) restituisce un elenco dei Oggetti WorkInfo che possono essere utilizzati per determinare lo stato di lavoro attuale.

Il seguente codice mostra come aggiungere una "pulizia" tag alla tua attività:

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilderM<yWork(>)
   .addTag("cleanup")
   .build()

Java

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
       .addTag("cleanup")
       .build();

Infine, è possibile aggiungere più tag a una singola richiesta di lavoro. Internamente vengono archiviati come un insieme di stringhe. Per ottenere l'insieme di tag associati WorkRequest puoi utilizzare WorkInfo.getTag().

Dalla tua classe Worker, puoi recuperare il relativo insieme di tag tramite AscoltaableWorker.getTag().

Assegna dati di input

Per svolgere il proprio lavoro potrebbero essere necessari dati di input. Ad esempio, lavora gestire il caricamento di un'immagine potrebbe richiedere che l'URI dell'immagine venga caricato come di testo.

I valori di input vengono memorizzati come coppie chiave-valore in un oggetto Data e possono essere impostati sulla richiesta di lavoro. WorkManager consegnerà l'input Data a il tuo lavoro quando lo esegue. Il corso Worker può accedere gli argomenti di input richiamando Worker.getInputData(). La il seguente codice mostra come creare un'istanza Worker che richiede dati di input e come inviarli nella richiesta di lavoro.

Kotlin

// Define the Worker requiring input
class UploadWork(appContext: Context, workerParams: WorkerParameters)
   : Worker(appContext, workerParams) {

   override fun doWork(): Result {
       val imageUriInput =
           inputData.getString("IMAGE_URI") ?: return Result.failure()

       uploadFile(imageUriInput)
       return Result.success()
   }
   ...
}

// Create a WorkRequest for your Worker and sending it input
val myUploadWork = OneTimeWorkRequestBuilderU<ploadWork(>)
   .setInputData(workDataOf(
       "IMAGE_URI" to "http://..."
   ))
   .build()

Java

// Define the Worker requiring input
public class UploadWork extends Worker {

   public UploadWork(Context appContext, WorkerParameters workerParams) {
       super(appContext, workerParams);
   }

   @NonNull
   @Override
   public Result doWork() {
       String imageUriInput = getInputData().getString("IMAGE_URI");
       if(imageUriInput == null) {
           return Result.failure();
       }

       uploadFile(imageUriInput);
       return Result.success();
   }
   ...
}

// Create a WorkRequest for your Worker and sending it input
WorkRequest myUploadWork =
      new OneTimeWorkRequest.Builder(UploadWork.class)
           .setInputData(
               new Data.Builder()
                   .putString("IMAGE_URI", "http://...")
                   .build()
           )
           .build();

Analogamente, la classe Data può essere utilizzata per generare un valore restituito. I dati di input e per ulteriori informazioni, consulta la sezione Parametri di input e sono stati restituiti.

Passaggi successivi

Nella pagina Stati e osservazione, scoprirai di più sugli stati di lavoro e come monitorare l'avanzamento del lavoro.