Aufgaben verwalten

Nachdem Sie Worker und WorkRequest definiert haben, besteht der letzte Schritt darin, Ihre Arbeit in die Warteschlange zu stellen. Am einfachsten können Sie die Arbeit in die Warteschlange stellen, indem Sie die WorkManager-Methode enqueue() aufrufen und die WorkRequest übergeben, die Sie ausführen möchten.

Kotlin


val myWork: WorkRequest = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork)

Java


WorkRequest myWork = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork);

Achten Sie darauf, Aufgaben in die Warteschlange zu stellen, um Duplikate zu vermeiden. Beispielsweise kann eine Anwendung versuchen, ihre Logs alle 24 Stunden auf einen Back-End-Dienst hochzuladen. Wenn Sie nicht aufpassen, stellen Sie dieselbe Aufgabe unter Umständen mehrmals in die Warteschlange, obwohl der Job nur einmal ausgeführt werden muss. Zu diesem Zweck können Sie die Arbeit als einzigartige Arbeit planen.

Einzigartige Arbeit

Einzigartige Arbeit ist ein leistungsstarkes Konzept, das garantiert, dass Sie jeweils nur eine Arbeitsinstanz mit einem bestimmten Namen haben. Im Gegensatz zu IDs sind eindeutige Namen für Menschen lesbar und werden vom Entwickler angegeben und nicht automatisch von WorkManager generiert. Im Gegensatz zu Tags werden eindeutige Namen nur einer einzelnen Arbeitsinstanz zugeordnet.

Einzigartige Arbeiten können sowohl bei einmaligen als auch bei regelmäßigen Arbeiten angewandt werden. Sie können einen eindeutigen Ablauf erstellen, indem Sie eine dieser Methoden aufrufen, je nachdem, ob Sie wiederkehrende oder einmalige Arbeiten planen.

Beide Methoden akzeptieren drei Argumente:

  • uniqueWorkName: Ein String, der zur eindeutigen Identifizierung der Arbeitsanfrage verwendet wird.
  • existingWorkPolicy: Ein enum, das WorkManager mitteilt, was zu tun ist, wenn es bereits eine unvollendete Arbeitskette mit diesem eindeutigen Namen gibt. Weitere Informationen finden Sie in der Richtlinie zur Konfliktlösung.
  • work: der zu planende Wert (WorkRequest).

Mit eigenen Arbeiten können wir das zuvor erwähnte Problem mit doppelten Terminbuchungen beheben.

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);

Wenn der Code jetzt ausgeführt wird, während sich bereits ein sendLogs-Job in der Warteschlange befindet, wird der vorhandene Job beibehalten und es wird kein neuer Job hinzugefügt.

Eindeutige Arbeitssequenzen können auch nützlich sein, wenn Sie eine lange Kette von Aufgaben schrittweise aufbauen müssen. In einer Bildbearbeitungs-App können Nutzer beispielsweise eine lange Reihe von Aktionen rückgängig machen. Jeder dieser Schritte zum Rückgängigmachen kann eine Weile dauern, muss aber in der richtigen Reihenfolge ausgeführt werden. In diesem Fall könnte die Anwendung eine Kette vom Typ "Rückgängig machen" erstellen und jeden Vorgang zum Rückgängigmachen nach Bedarf an die Kette anhängen. Weitere Informationen finden Sie unter Kettenarbeiten.

Richtlinie zur Konfliktlösung

Beim Planen einmaliger Arbeiten müssen Sie WorkManager mitteilen, welche Aktion bei einem Konflikt ausgeführt werden soll. Dazu übergeben Sie beim Einreihen der Arbeit eine enum.

Für einmalige Arbeiten stellen Sie eine ExistingWorkPolicy bereit, die vier Optionen für die Verarbeitung des Konflikts unterstützt.

  • REPLACE vorhandene Arbeit mit der neuen Arbeit. Mit dieser Option wird die vorhandene Arbeit abgebrochen.
  • KEEP vorhandene Arbeit und ignorieren die neue.
  • APPEND die neue Arbeit an das Ende der vorhandenen Arbeit an. Durch diese Richtlinie wird Ihre neue Arbeit an die vorhandene Arbeit verkettet und nach Abschluss der vorhandenen Arbeit ausgeführt.

Die vorhandene Arbeit wird zu einer Voraussetzung für das neue Werk. Wenn das vorhandene Werk zu CANCELLED oder FAILED wird, ist das neue Werk ebenfalls CANCELLED oder FAILED. Wenn die neue Arbeit unabhängig vom Status der vorhandenen Arbeit ausgeführt werden soll, verwenden Sie stattdessen APPEND_OR_REPLACE.

  • APPEND_OR_REPLACE funktioniert ähnlich wie APPEND, mit der Ausnahme, dass es nicht vom erforderlichen Arbeitsstatus abhängt. Wenn die vorhandene Arbeit CANCELLED oder FAILED ist, wird sie trotzdem ausgeführt.

Für Arbeiten in der Periode stellst du ein ExistingPeriodicWorkPolicy bereit, das zwei Optionen unterstützt: REPLACE und KEEP. Diese Optionen funktionieren genauso wie die „existingWorkPolicy“-Entsprechungen.

Ihre Arbeit beobachten

Nachdem die Arbeit in die Warteschlange gestellt wurde, können Sie ihren Status jederzeit prüfen, indem Sie WorkManager über die zugehörige name, id oder eine verknüpfte tag abfragen.

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


Die Abfrage gibt ein ListenableFuture eines WorkInfo-Objekts zurück, das den id des Werks, dessen Tags, den aktuellen State und jeden Ausgabedatensatz über Result.success(outputData) enthält.

Mit einer LiveData-Variante jeder der Methoden können Sie Änderungen am WorkInfo beobachten, indem Sie einen Listener registrieren. Wenn Sie beispielsweise dem Nutzer eine Nachricht anzeigen möchten, wenn einige Vorgänge erfolgreich abgeschlossen wurden, können Sie diese so einrichten:

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();
   }
});

Komplexe Arbeitsabfragen

WorkManager 2.4.0 und höher unterstützt komplexe Abfragen für Jobs in der Warteschlange mit WorkQuery-Objekten. WorkQuery unterstützt die Abfrage von Aufgaben anhand einer Kombination aus Tags, Status und eindeutigem Arbeitsnamen.

Das folgende Beispiel zeigt, wie Sie alle Arbeiten mit dem Tag "syncTag" finden, das sich im Status FAILED oder CANCELLED befindet und einen eindeutigen Arbeitsnamen entweder "preProcess" oder "sync" hat.

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);

Jede Komponente (Tag, Status oder Name) in einem WorkQuery ist AND-verknüpft mit den anderen. Jeder Wert in einer Komponente ist OR-eddig. Beispiel: (name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...).

WorkQuery funktioniert auch mit dem LiveData-Äquivalent getWorkInfosLiveData().

Arbeit abbrechen und beenden

Wenn Sie Ihre in die Warteschlange eingereihte Arbeit nicht mehr benötigen, können Sie deren Abbruch anfordern. Arbeit kann durch name, id oder eine damit verknüpfte tag abgebrochen werden.

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");

Intern prüft WorkManager die State der Arbeit. Wenn die Arbeit bereits fertig ist, passiert nichts. Andernfalls wird der Status der Arbeit in CANCELLED geändert und die Arbeit wird in der Zukunft nicht ausgeführt. Alle WorkRequest-Jobs, die von dieser Arbeit abhängig sind, sind ebenfalls CANCELLED.

Derzeit erhält RUNNING einen Aufruf an ListenableWorker.onStopped(). Überschreiben Sie diese Methode, um eine mögliche Bereinigung abzuwickeln. Weitere Informationen finden Sie unter Ausführen von Workern beenden.

Ausführenden Worker anhalten

Das Ausführen von Worker kann aus verschiedenen Gründen von WorkManager angehalten werden:

  • Sie haben die Stornierung explizit angefordert (z. B. durch Aufrufen von WorkManager.cancelWorkById(UUID)).
  • Im Fall von eindeutigen Arbeiten haben Sie explizit eine neue WorkRequest mit einem ExistingWorkPolicy von REPLACE in die Warteschlange gestellt. Das alte WorkRequest gilt sofort als storniert.
  • Die Einschränkungen Ihrer Arbeit werden nicht mehr erfüllt.
  • Das System hat deine App angewiesen, deine Arbeit aus irgendeinem Grund zu beenden. Dies kann passieren, wenn Sie die Ausführungsfrist von 10 Minuten überschreiten. Die Arbeit wird für eine spätere Wiederholung geplant.

Unter diesen Bedingungen wird Ihr Worker angehalten.

Sie sollten alle laufenden Arbeiten gemeinsam abbrechen und alle Ressourcen freigeben, an denen der Worker sich hält. Zum Beispiel sollten Sie an dieser Stelle offene Handles für Datenbanken und Dateien schließen. Ihnen stehen zwei Mechanismen zur Verfügung, um herauszufinden, wann Ihr Worker angehalten wird.

onStopped()-Callback

WorkManager ruft ListenableWorker.onStopped() auf, sobald der Worker angehalten wurde. Überschreiben Sie diese Methode, um alle Ressourcen zu schließen, an denen Sie möglicherweise festhalten.

Eigenschaft "isStopped()"

Sie können die Methode ListenableWorker.isStopped() aufrufen, um zu prüfen, ob der Worker bereits angehalten wurde. Wenn Sie lang andauernde oder sich wiederholende Vorgänge in Ihrem Worker ausführen, sollten Sie dieses Attribut regelmäßig überprüfen und es als Signal dafür verwenden, die Arbeit so schnell wie möglich zu beenden.

Hinweis:WorkManager ignoriert die Result, die von einem Worker festgelegt wurde, der das onStop-Signal erhalten hat, da der Worker bereits als beendet gilt.