Aufgaben verwalten

Nachdem Sie Ihre Worker und Ihre WorkRequest definiert haben, besteht der letzte Schritt darin, die Arbeit in die Warteschlange zu stellen. Die einfachste Möglichkeit, Arbeit in die Warteschlange zu stellen, ist der Aufruf der enqueue()-Methode von WorkManager und die Übergabe des auszuführenden WorkRequest.

Kotlin

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

Java

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

Seien Sie vorsichtig, wenn Sie Arbeit in die Warteschlange stellen, um Duplizierungen zu vermeiden. Eine App kann beispielsweise versuchen, ihre Logs alle 24 Stunden in einen Backend-Dienst hochzuladen. Wenn Sie nicht aufpassen, stellen Sie die gleiche Aufgabe möglicherweise mehrmals in die Warteschlange, obwohl der Job nur einmal ausgeführt werden muss. Um dies zu erreichen, können Sie die Arbeit als eindeutige Arbeit planen.

Eindeutige Arbeit

Eindeutige 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 menschenlesbar und werden vom Entwickler angegeben, anstatt automatisch von WorkManager generiert zu werden. Im Gegensatz zu Tags sind eindeutige Namen nur einer einzelnen Arbeitsinstanz zugeordnet.

Eindeutige Arbeit kann sowohl auf einmalige als auch auf periodische Arbeit angewendet werden. Sie können eine eindeutige Arbeitssequenz erstellen, indem Sie eine dieser Methoden aufrufen, je nachdem, ob Sie wiederholte oder einmalige Arbeit planen.

Beide Methoden akzeptieren drei Argumente:

  • uniqueWorkName – Ein String, mit dem die Arbeits anfrage eindeutig identifiziert wird.
  • existingWorkPolicy – Ein enum, das WorkManager anweist, was zu tun ist , wenn bereits eine unvollständige Arbeitskette mit diesem eindeutigen Namen vorhanden ist. Weitere Informationen finden Sie unter Richtlinie zur Konfliktlösung.
  • work – das zu planende WorkRequest.

Mit eindeutiger Arbeit können wir das Problem mit der doppelten Planung beheben, das wir zuvor festgestellt haben.

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 kein neuer Job hinzugefügt.

Eindeutige Arbeitssequenzen können auch nützlich sein, wenn Sie eine lange Kette von Aufgaben schrittweise aufbauen müssen. Mit einer Fotobearbeitungs-App können Nutzer beispielsweise eine lange Kette von Aktionen rückgängig machen. Jeder dieser Rückgängig-Vorgänge kann einige Zeit dauern, muss aber in der richtigen Reihenfolge ausgeführt werden. In diesem Fall könnte die App eine „Rückgängig“-Kette erstellen und bei Bedarf jeden Rückgängig-Vorgang an die Kette anhängen. Weitere Informationen finden Sie unter Arbeit verketten.

Richtlinie zur Konfliktlösung

Wenn Sie eindeutige Arbeit planen, müssen Sie WorkManager mitteilen, welche Aktion bei einem Konflikt ausgeführt werden soll. Dazu übergeben Sie beim Einreihen der Arbeit in die Warteschlange ein Enum.

Für einmalige Arbeit geben Sie ein ExistingWorkPolicy an, das vier Optionen für die Behandlung des Konflikts unterstützt.

  • REPLACE : Ersetzt die vorhandene Arbeit durch die neue Arbeit. Mit dieser Option wird die vorhandene Arbeit abgebrochen.
  • KEEP : Behält die vorhandene Arbeit bei und ignoriert die neue Arbeit.
  • APPEND : Fügt die neue Arbeit am Ende der vorhandenen Arbeit an. Mit dieser Richtlinie wird die neue Arbeit an die vorhandene Arbeit angehängt und nach Abschluss der vorhandenen Arbeit ausgeführt.

Die vorhandene Arbeit wird zu einer Voraussetzung für die neue Arbeit. Wenn die vorhandene Arbeit CANCELLED oder FAILED ist, ist auch die neue Arbeit 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, ist aber nicht vom Status der Voraussetzung abhängig. Wenn die vorhandene Arbeit CANCELLED oder FAILED ist, wird die neue Arbeit trotzdem ausgeführt.

Für periodische Arbeit geben Sie eine ExistingPeriodicWorkPolicy an, die zwei Optionen unterstützt: REPLACE und KEEP. Diese Optionen funktionieren genauso wie ihre Entsprechungen in der ExistingWorkPolicy.

Arbeit beobachten

Nachdem Sie Arbeit in die Warteschlange gestellt haben, können Sie den Status jederzeit prüfen, indem Sie WorkManager nach name, id oder einem zugehörigen 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 die id der Arbeit, ihre Tags, ihren aktuellen State und alle Ausgabedatasets mit Result.success(outputData) enthält.

Mit den LiveData- und Flow -Varianten der einzelnen Methoden können Sie Änderungen an der WorkInfo beobachten, indem Sie einen Listener registrieren. Wenn Sie dem Nutzer beispielsweise eine Nachricht anzeigen möchten, wenn eine Arbeit erfolgreich abgeschlossen wurde, können Sie das so einrichten:

Kotlin

workManager.getWorkInfoByIdFlow(syncWorker.id)
          .collect{ 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 in die Warteschlange gestellte Jobs mit WorkQuery-Objekten. Mit WorkQuery können Sie Arbeit anhand einer Kombination aus Tag(s), Status und eindeutigem Arbeitsnamen abfragen.

Im folgenden Beispiel wird gezeigt, wie Sie alle Arbeiten mit dem Tag „syncTag“, finden, die den Status FAILED oder CANCELLED haben und deren eindeutiger Arbeitsname entweder „preProcess“ oder „sync“ ist.

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 einer WorkQuery wird mit den anderen Komponenten mit AND verknüpft. Jeder Wert in einer Komponente wird OR-ed. Beispiel: (name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...).

WorkQuery funktioniert auch mit dem LiveData-Äquivalent, getWorkInfosLiveData(), und dem Flow-Äquivalent getWorkInfosFlow().

Arbeit abbrechen und beenden

Wenn Sie nicht mehr möchten, dass die zuvor in die Warteschlange gestellte Arbeit ausgeführt wird, können Sie sie abbrechen. Arbeit kann anhand von name, id oder einem zugehörigen 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");

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

RUNNING Arbeit erhält einen Aufruf an ListenableWorker.onStopped(). Überschreiben Sie diese Methode, um potenzielle Bereinigungen zu verarbeiten. Weitere Informationen finden Sie unter Laufenden Worker beenden.

Laufenden Worker beenden

Es gibt verschiedene Gründe, warum ein laufender Worker von WorkManager beendet werden kann:

  • Sie haben explizit darum gebeten, ihn abzubrechen (z. B. durch Aufrufen von WorkManager.cancelWorkById(UUID)).
  • Bei eindeutiger Arbeit, haben Sie explizit ein neues WorkRequest mit einer ExistingWorkPolicy von REPLACE in die Warteschlange gestellt. Das alte WorkRequest wird sofort als abgebrochen betrachtet.
  • Die Einschränkungen für Ihre Arbeit werden nicht mehr erfüllt.
  • Das System hat Ihre App aus irgendeinem Grund angewiesen, die Arbeit zu beenden. Das kann passieren, wenn Sie die Ausführungsfrist von 10 Minuten überschreiten. Die Arbeit wird zu einem späteren Zeitpunkt zur Wiederholung geplant.

Unter diesen Bedingungen wird Ihr Worker beendet.

Sie sollten alle laufenden Arbeiten kooperativ abbrechen und alle Ressourcen freigeben, die Ihr Worker verwendet. Beispielsweise sollten Sie an dieser Stelle offene Handles für Datenbanken und Dateien schließen. Es gibt zwei Mechanismen, mit denen Sie feststellen können, wann Ihr Worker beendet wird.

onStopped()-Callback

WorkManager invokes ListenableWorker.onStopped() sobald Ihr Worker beendet wurde. Überschreiben Sie diese Methode, um alle Ressourcen zu schließen, die Sie möglicherweise verwenden.

isStopped()-Property

Sie können die ListenableWorker.isStopped() Methode aufrufen, um zu prüfen, ob Ihr Worker bereits beendet wurde. Wenn Sie in Ihrem Worker Vorgänge mit langer Ausführungszeit oder wiederholte Vorgänge ausführen, sollten Sie diese Property häufig prüfen und sie als Signal verwenden, um die Arbeit so schnell wie möglich zu beenden.

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