Una volta definita la tua
Worker
e
WorkRequest
,
l'ultimo passaggio è accodare il lavoro. Il modo più semplice per accodare il lavoro
è chiamare il metodo enqueue()
di WorkManager, passando il valore WorkRequest
che vuoi eseguire.
Kotlin
val myWork: WorkRequest = // ... OneTime or PeriodicWork WorkManager.getInstance(requireContext()).enqueue(myWork)
Java
WorkRequest myWork = // ... OneTime or PeriodicWork WorkManager.getInstance(requireContext()).enqueue(myWork);
Fai attenzione quando accoda i lavori per evitare duplicati. Ad esempio, un'app potrebbe tentare di caricare e i propri log a un servizio di backend ogni 24 ore. Se non fai attenzione, potresti finiscono per accodare la stessa attività molte volte, anche se il lavoro deve solo vengono eseguiti una sola volta. Per raggiungere questo obiettivo, puoi pianificare il lavoro come lavoro unico.
Opera esclusiva
Il lavoro unico è un concetto potente che garantisce di avere solo uno istanza di lavoro con un nome specifico alla volta. A differenza degli ID, i nomi univoci sono leggibili da una persona e specificati dallo sviluppatore anziché essere generati automaticamente da WorkManager. Non mi piace tag, univoci sono associati a una sola istanza di lavoro.
I lavori unici possono essere applicati sia al lavoro una tantum sia a quello periodico. Puoi creare un una sequenza di lavoro univoca chiamando uno di questi metodi, a seconda che stai pianificando un lavoro ricorrente o un lavoro una tantum.
WorkManager.enqueueUniqueWork()
per un lavoro una tantumWorkManager.enqueueUniquePeriodicWork()
per lavori periodici
Entrambi i metodi accettano tre argomenti:
- uniqueWorkName: un
String
utilizzato per identificare in modo univoco l'opera richiesta. - existingWorkPolicy: un
enum
che indica a WorkManager cosa fare se esiste già una catena di lavori non completata con quel nome univoco. Consulta norme relative alla risoluzione dei conflitti per ulteriori informazioni. - work: i
WorkRequest
da pianificare.
Utilizzando un lavoro unico, possiamo risolvere il problema di pianificazione duplicato di cui abbiamo parlato in precedenza.
Kotlin
val sendLogsWorkRequest = PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS) .setConstraints(Constraints.Builder() .setRequiresCharging(true) .build() ) .build() WorkManager.getInstance(this).enqueueUniquePeriodicWork( "sendLogs", ExistingPeriodicWorkPolicy.KEEP, sendLogsWorkRequest )
Java
PeriodicWorkRequest sendLogsWorkRequest = new PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS) .setConstraints(new Constraints.Builder() .setRequiresCharging(true) .build() ) .build(); WorkManager.getInstance(this).enqueueUniquePeriodicWork( "sendLogs", ExistingPeriodicWorkPolicy.KEEP, sendLogsWorkRequest);
Ora, se il codice viene eseguito mentre un job sendLogs è già in coda, lo stato di un job viene mantenuto e non ne viene aggiunto di nuovi.
Le sequenze di lavoro univoche possono essere utili anche se devi creare gradualmente un una lunga catena di attività. Ad esempio, un'app di fotoritocco potrebbe consentire agli utenti di annullare un una lunga catena di azioni. Ognuna di queste operazioni di annullamento potrebbe richiedere del tempo, ma devono essere eseguite nell'ordine corretto. In questo caso, l'app potrebbe crea un'operazione di annullamento e aggiungere alla catena ogni operazione di annullamento in base alle esigenze. Consulta la sezione Catena di lavori per ulteriori informazioni.
Norme per la risoluzione dei conflitti
Quando pianifichi un lavoro unico, devi indicare a WorkManager quale azione intraprendere quando se si verifica un conflitto. Per farlo, passi un'enumerazione quando accoda il lavoro.
Per i lavori una tantum, fornisci un
ExistingWorkPolicy
, che
supporta 4 opzioni per la gestione del conflitto.
REPLACE
esistente con il nuovo lavoro. Questa opzione annulla il lavoro esistente.KEEP
lavori esistenti e ignorare il nuovo lavoro.APPEND
il nuovo lavoro per la fine del lavoro esistente. Grazie a queste norme, il tuo nuovo lavoro verrà collegato al e il lavoro esistente, in esecuzione al termine di quello esistente.
Il lavoro esistente diventa un prerequisito per il nuovo lavoro. Se il lavoro esistente
diventa CANCELLED
o FAILED
, il nuovo lavoro è anche CANCELLED
o FAILED
.
Se vuoi che il nuovo lavoro venga eseguito a prescindere dallo stato di quello esistente,
usa invece APPEND_OR_REPLACE
.
APPEND_OR_REPLACE
funziona in modo simile aAPPEND
, ad eccezione del fatto che non dipende da stato di lavoro prerequisito. Se l'opera esistente èCANCELLED
oFAILED
, il nuovo lavoro è ancora in esecuzione.
Per i lavori in stile, fornisci un
ExistingPeriodicWorkPolicy
,
che supporta due opzioni, REPLACE
e KEEP
. Queste opzioni funzionano allo stesso modo
come controparti CurrentWorkPolicy.
Osservare il tuo lavoro
In qualsiasi momento dopo aver accodato il lavoro, puoi verificarne lo stato eseguendo query
WorkManager in base al rispettivo name
, id
o a un tag
associato.
Kotlin
// by id workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo> // by name workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>> // by tag workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>
Java
// by id workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo> // by name workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>> // by tag workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>
La query restituisce un
ListenableFuture
di un oggetto WorkInfo
, che include
id
dell'opera, i suoi tag, i suoi
State
corrente ed eventuali dati di output
imposta tramite
Result.success(outputData)
.
Una variante LiveData
di ciascuno
ti consente di osservare le modifiche a WorkInfo
registrando
un listener. Ad esempio, se vuoi mostrare un messaggio all'utente quando
alcuni lavori vengono completati correttamente, puoi configurarlo nel seguente modo:
Kotlin
workManager.getWorkInfoByIdLiveData(syncWorker.id) .observe(viewLifecycleOwner) { workInfo -> if(workInfo?.state == WorkInfo.State.SUCCEEDED) { Snackbar.make(requireView(), R.string.work_completed, Snackbar.LENGTH_SHORT) .show() } }
Java
workManager.getWorkInfoByIdLiveData(syncWorker.id) .observe(getViewLifecycleOwner(), workInfo -> { if (workInfo.getState() != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) { Snackbar.make(requireView(), R.string.work_completed, Snackbar.LENGTH_SHORT) .show(); } });
Query di lavoro complesse
WorkManager 2.4.0 e versioni successive supporta query complesse per i lavori accodati utilizzando
WorkQuery
oggetti. WorkQuery supporta
query per il lavoro in base a una combinazione di tag, stato e nome univoco dell'opera.
L'esempio seguente mostra come trovare tutte le operazioni con il tag "syncTag",
nello stato FAILED
o CANCELLED
e con un nome di lavoro univoco
"preProcess" o "sync".
Kotlin
val workQuery = WorkQuery.Builder .fromTags(listOf("syncTag")) .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)) .addUniqueWorkNames(listOf("preProcess", "sync") ) .build() val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery)
Java
WorkQuery workQuery = WorkQuery.Builder .fromTags(Arrays.asList("syncTag")) .addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)) .addUniqueWorkNames(Arrays.asList("preProcess", "sync") ) .build(); ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);
Ogni componente (tag, stato o nome) in un elemento WorkQuery
è AND
-ed con la classe
altri. Ogni valore in un componente è OR
-ed. Ad esempio: (name1 OR name2
OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)
.
WorkQuery
funziona anche con l'equivalente LiveData,
getWorkInfosLiveData()
Annullamento e interruzione del lavoro
Se non hai più bisogno di eseguire il lavoro precedentemente accodato, puoi richiederlo
potrebbe essere annullato. Il lavoro può essere annullato dal relativo name
, id
o da un tag
associate.
Kotlin
// by id workManager.cancelWorkById(syncWorker.id) // by name workManager.cancelUniqueWork("sync") // by tag workManager.cancelAllWorkByTag("syncTag")
Java
// by id workManager.cancelWorkById(syncWorker.id); // by name workManager.cancelUniqueWork("sync"); // by tag workManager.cancelAllWorkByTag("syncTag");
Dietro le quinte, WorkManager controlla
State
del lavoro. Se l'opera è
finito,
non accade nulla. Altrimenti, lo stato del lavoro viene modificato in
CANCELLED
e il lavoro
non verranno eseguite in futuro. Qualsiasi
WorkRequest
job dipendenti
in questo lavoro
anche CANCELLED
.
Lavoro attualmente in RUNNING
riceve una chiamata a
ListenableWorker.onStopped()
.
Sostituisci questo metodo per gestire qualsiasi potenziale pulizia. Vedi interrompere una
worker in esecuzione per ulteriori informazioni.
Arresta un worker in esecuzione
Esistono diversi motivi per cui WorkManager potrebbe interrompere l'esecuzione di Worker
:
- Hai richiesto esplicitamente l'annullamento (chiamando
WorkManager.cancelWorkById(UUID)
, ad esempio). - Nel caso di un lavoro unico,
hai accodato esplicitamente un nuovo
WorkRequest
con unExistingWorkPolicy
diREPLACE
IlWorkRequest
precedente viene immediatamente considerato annullato. - I vincoli del tuo lavoro non sono più soddisfatti.
- Il sistema ha chiesto all'app di interrompere il lavoro per qualche motivo. Questo può si verificano se superi la scadenza dell'esecuzione di 10 minuti. L'opera è e pianificato per un nuovo tentativo in un secondo momento.
In queste condizioni, il worker viene arrestato.
Dovresti interrompere in collaborazione il lavoro in corso e rilasciare eventuali e le risorse a cui sta tenendo il tuo worker. Ad esempio, dovresti chiudere a database e file a questo punto. Esistono due meccanismi a livello a disposizione per capire quando il worker si arresta.
Callback onSstop()
Richiami WorkManager
ListenableWorker.onStopped()
non appena il worker viene arrestato. Sostituisci questo metodo per chiudere
le eventuali risorse a cui tieni.
proprietà isSstop()
Puoi chiamare il
ListenableWorker.isStopped()
per controllare se il worker è già stato interrotto. Se
eseguendo operazioni a lunga esecuzione o ripetitive nel Worker,
controlla spesso questa proprietà e usala come indicatore per interrompere il lavoro appena possibile
il più possibile.
Nota: WorkManager ignora la
Result
impostata da un worker
che ha ricevuto l'indicatore onStop, perché il worker è già considerato
è stata interrotta.