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.
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
eEXPONENTIAL
.
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.