Überprüfen Sie, ob WorkManager bereits eingeplant ist

Lesezeit: 8 Minuten

Wie kann ich überprüfen, ob WorkManager ist bereits geplant.

Hier ist mein Code für diesen Zeitplan WorkManager.

public static void scheduleWork() {
    PeriodicWorkRequest.Builder photoCheckBuilder =
            new PeriodicWorkRequest.Builder(WorkManagerService.class, TIME_INTERVAL_IN_SECONDS,
                    TimeUnit.SECONDS);
    PeriodicWorkRequest photoCheckWork = photoCheckBuilder.build();
    WorkManager instance = WorkManager.getInstance();
    if (instance != null) {
        instance.enqueueUniquePeriodicWork("TAG", ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
    }
}

Ich rufe scheduleWork() in onCreate() von meinen Application Klasse. Sogar ich kann überprüfen, ob mein Dienst ausgeführt wird oder nicht diese Methode. Aber ich möchte WorkManager nicht planen, wenn es bereits geplant ist, um Inkonsistenzen in der geplanten Zeit zu beseitigen.

Wie

if(!workManagerIsScheduled())
   {
     scheduleWork();
   }

Irgendwelche Lösungen?

  • Sie können den Status der Arbeitsanfrage abrufen … zur Überprüfung

    – Mann

    31. Juli 2018 um 11:55 Uhr

  • Hast du das versucht?

    – Mann

    31. Juli 2018 um 12:00 Uhr

  • Siehe Antwort @Man

    – Khemraj Sharma

    31. Juli 2018 um 12:11 Uhr

  • Es ist nicht erforderlich zu prüfen, ob Worker bereits ausgeführt wird, da Sie instance.enqueueUniquePeriodicWork() mit ‘ExistingPeriodicWorkPolicy.KEEP’ verwenden. Es wird die neue PeriodicWorkRequest nur ausführen, wenn es keine ausstehende Arbeit gibt, die mit uniqueWorkName gekennzeichnet ist.

    – Rai_Gaurav

    31. Juli 2018 um 12:11 Uhr

  • „ExistingPeriodicWorkPolicy.KEEP“ ist für eine bestimmte Aufgabe, nicht für die Arbeit. Wenn ein Dienst seine Arbeit erledigt, hält dieses Flag den Dienst am Laufen, bis er seine Arbeit beendet hat.

    – Khemraj Sharma

    31. Juli 2018 um 12:13 Uhr

Benutzer-Avatar
Khemraj Sharma

Aktualisieren

Wenn Sie den bereits ausgeführten Arbeitsmanager überprüfen müssen, nur weil Sie keine doppelten Arbeiten wünschen. Sie können einfach verwenden enqueueUniquePeriodicWork()

Mit dieser Methode können Sie eine PeriodicWorkRequest mit eindeutigem Namen in die Warteschlange einreihen, wobei jeweils nur eine PeriodicWorkRequest mit einem bestimmten Namen aktiv sein kann. Beispielsweise möchten Sie möglicherweise, dass nur ein Synchronisierungsvorgang aktiv ist. Wenn eines aussteht, können Sie es ausführen lassen oder durch Ihre neue Arbeit ersetzen.

Sie müssen sich also keine Gedanken über Doppelarbeit bei Werken machen.

 workmanager.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
  • Wobei TAG ein eindeutiger Name ist, anhand dessen der Arbeitsmanager auf Duplikate prüft.
  • Du kannst wählen zwischen ExistingPeriodicWorkPolicy.KEEP und ExistingPeriodicWorkPolicy.REPLACE.

Originalbeitrag

Ich habe diese Methode erstellt, als ich keine gefunden habe.

Überprüfen Sie, ob die Arbeit von TAG ausgeführt wird

if (your_work_manager.version >= 1.0.0-alpha11)

private boolean isWorkScheduled(String tag) {
    WorkManager instance = WorkManager.getInstance();
    ListenableFuture<List<WorkInfo>> statuses = instance.getWorkInfosByTag(tag);
    try {
        boolean running = false;
        List<WorkInfo> workInfoList = statuses.get();
        for (WorkInfo workInfo : workInfoList) {
            WorkInfo.State state = workInfo.getState();
            running = state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;
        }
        return running;
    } catch (ExecutionException e) {
        e.printStackTrace();
        return false;
    } catch (InterruptedException e) {
        e.printStackTrace();
        return false;
    }
}

if (your_work_manager.version < 1.0.0-alpha11)

private boolean isWorkScheduled(String tag) {
    WorkManager instance = WorkManager.getInstance();
    LiveData<List<WorkStatus>> statuses = instance.getStatusesByTag(tag);
    if (statuses.getValue() == null) return false;
    boolean running = false;
    for (WorkStatus workStatus : statuses.getValue()) {
        running = workStatus.getState() == State.RUNNING | workStatus.getState() == State.ENQUEUED;
    }
    return running;
}

Es wird zurückkehren true wenn etwas von seiner Aufgabe ist RUNNING oder ENQUEUED.

Beispielcode

public static final String TAG_MY_WORK = "mywork";

if(!isWorkScheduled(TAG_MY_WORK)) { // check if your work is not already scheduled
    scheduleWork(TAG_MY_WORK); // schedule your work
}

public static void scheduleWork(String tag) {
    PeriodicWorkRequest.Builder photoCheckBuilder =
            new PeriodicWorkRequest.Builder(WorkManagerService.class, TIME_INTERVAL_IN_SECONDS,
                    TimeUnit.SECONDS);
    PeriodicWorkRequest photoCheckWork = photoCheckBuilder.build();
    WorkManager instance = WorkManager.getInstance();
    instance.enqueueUniquePeriodicWork(tag, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
}

  • Hallo Khemraj, Ihre Lösung gibt mir diese Art von Fehler androidx.work.impl.utils.futures.SettableFuture kann nicht in android.arch.lifecycle.LiveData umgewandelt werden Es kann nicht umgewandelt werden LiveData> statuses = instance.getStatusesByTag( Schild);

    – Rahul Patil

    3. November 2018 um 7:12 Uhr

  • Wenn Sie den Status der Livedaten abrufen möchten, müssen Sie gemäß der neuen API „getStatusesByTag(tag)“ in „getStatusesByTagLiveData(tag)“ ändern.

    – Saurabh

    6. November 2018 um 6:14 Uhr


  • Wie wäre es mit State.BLOCKED ?. Warum wird es nicht zur Überprüfung verwendet? developer.android.com/topic/libraries/architecture/workmanager/…. Es erklärt, dass eine Aufgabe darauf wartet, dass andere Aufgaben beendet werden, die der Reihe nach ausgeführt werden sollen. Idealerweise sollten wir nicht verwenden !state.isFinished() um alle Tasks zu überprüfen, die sich noch in der Warteschlange befinden oder ausgeführt werden oder auf die Ausführung warten.

    – Sreejith B. Naick

    28. Mai 2019 um 14:58 Uhr


  • Beim Überprüfen von instance.getWorkInfosByTag(tag) wird immer eine leere Liste zurückgegeben, daher habe ich instance.getWorkInfosForUniqueWork(tag) verwendet und funktioniert in Abhängigkeiten -> Implementierung “androidx.work:work-runtime:2.2.0”

    – Sarah Kumar

    23. November 2019 um 13:19 Uhr


  • Du solltest benutzen running |= state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED; Andernfalls, running wird den Wert des letzten haben workInfo

    – Schild

    5. Februar 2020 um 12:23 Uhr

aus 1.0.0-alpha11 zusammen mit vielen Dingen Arbeitsstatus funktioniert nicht, es wurde entfernt und es ist eine bahnbrechende Änderung. Überprüfen Sie die Versionshinweise

WorkStatus wurde in WorkInfo umbenannt. Alle entsprechenden getStatus-Methodenvarianten wurden in die entsprechenden getWorkInfo-Varianten umbenannt. Dies ist eine bahnbrechende Änderung.

nach update auf alpha11 ist der funktionierende code.

private boolean isWorkScheduled(List<WorkInfo> workInfos) {

    boolean running = false;

    if (workInfos == null || workInfos.size() == 0) return false;

    for (WorkInfo workStatus : workInfos) {
        running = workStatus.getState() == WorkInfo.State.RUNNING | workStatus.getState() == WorkInfo.State.ENQUEUED;
    }

    return running;
}

Die akzeptierte Antwort ist falsch (schlecht, da sie stillschweigend fehlschlägt). Hier ist eine richtige Antwort

private boolean isWorkScheduled(String tag, Context context) {

        WorkManager instance = WorkManager.getInstance(context);
        ListenableFuture<List<WorkInfo>> statuses = instance.getWorkInfosByTag(tag);

        boolean running = false;
        List<WorkInfo> workInfoList = Collections.emptyList(); // Singleton, no performance penalty

        try {
            workInfoList = statuses.get();
        } catch (ExecutionException e) {
            Log.d(TAG, "ExecutionException in isWorkScheduled: " + e);
        } catch (InterruptedException e) {
            Log.d(TAG, "InterruptedException in isWorkScheduled: " + e);
        }

        for (WorkInfo workInfo : workInfoList) {
            WorkInfo.State state = workInfo.getState();
            running = running || (state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED);
        }
        return running;

Abgesehen von einigen Umgestaltungen, um irreführende Mehrfachrückgaben zu vermeiden, liegt der Fehler in dieser Zeile

running = state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;

Wenn Sie diese Zeile verwenden, erhalten Sie nur die zuletzt ausgewertete running. Ein Kommentar schlägt vor, den Operator zu verwenden =| stattdessen. Selbst wenn das Ergebnis korrekt sein sollte, wird der Code unklar und (leicht) suboptimal sein.
| ist ein bitweiser Operator und || ist ein logischer Operator. Die Operation, die wir ausführen möchten, ist logisch, nicht bitweise. Bei booleschen Werten | und || geben das gleiche Ergebnis, aber nur || ist eine Abkürzung, was in unserem Fall das beabsichtigte Verhalten ist.

Dieser Code funktioniert mindestens für WorkManager 2.5.0 und 2.6.0.

Benutzer-Avatar
David Sucharda

Seit dem 11. Oktober (2018) können Sie verwenden Hörbare Zukunft Anstatt von SynchronousWorkManager was entfernt wurde:

Mit ListenableFutures können Sie jetzt synchron abrufen und beobachten. Beispielsweise wurde WorkManager.enqueue() verwendet, um void zurückzugeben; es gibt jetzt ein ListenableFuture zurück. Sie können ListenableFuture.addListener(Runnable, Executor) oder ListenableFuture.get() aufrufen, um Code auszuführen, sobald der Vorgang abgeschlossen ist.

Weitere Informationen finden Sie hier.

Eine weitere Option kann die Verwendung sein ListenableWorker:

Eine Klasse, die in WorkManager asynchron arbeiten kann. In den meisten Fällen empfehlen wir die Verwendung von Worker, das eine einfache synchrone API bietet, die auf einem vordefinierten Hintergrundthread ausgeführt wird.

Es kehrt zurück Hörbare Zukunft nachdem Sie die Funktion startWork() aufgerufen haben.

Weitere Informationen finden Sie hier.

Ich habe die Antwort in diesem Beitrag gefunden und einige Änderungen vorgenommen.

In meinem Projekt; Ich sende alle 15 Minuten Standortinformationen an den Server. Und ich möchte WorkManager nicht planen, wenn es bereits geplant ist.

// Fırst I'm creating workRequest here.
   private void createWorkRequest() {
        Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
        PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder
                (LocationWorker.class, 15, TimeUnit.MINUTES)
                .setConstraints(constraints)
                .build();
        WorkManager.getInstance(this)
                .enqueueUniquePeriodicWork("sendLocation", ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest);
    }

// Then i'm learning the state of Work
    private WorkInfo.State getStateOfWork() {
        try {
            if (WorkManager.getInstance(this).getWorkInfosForUniqueWork("sendLocation").get().size() > 0) {
                return WorkManager.getInstance(this).getWorkInfosForUniqueWork("sendLocation")
                        .get().get(0).getState();
                // this can return WorkInfo.State.ENQUEUED or WorkInfo.State.RUNNING
                // you can check all of them in WorkInfo class.
            } else {
                return WorkInfo.State.CANCELLED;
            }
        } catch (ExecutionException e) {
            e.printStackTrace();
            return WorkInfo.State.CANCELLED;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return WorkInfo.State.CANCELLED;
        }
    }

// If work not ( ENQUEUED and RUNNING ) i'm running the work.
// You can check with other ways. It's up to you.
    private void startServerWork() {
        if (getStateOfWork() != WorkInfo.State.ENQUEUED && getStateOfWork() != WorkInfo.State.RUNNING) {
            createWorkRequest();
            Log.wtf("startLocationUpdates", ": server started");
        } else {
            Log.wtf("startLocationUpdates", ": server already working");
        }
    }

Ich denke, wir sollten alle sechs Status von WorkRequest by UniqueWorkName überprüfen. Wenn die Arbeitsanfrage in einen der Bundesstaaten fällt, sollten wir sie bereits als geplant markieren. Sie können auch einige Status in Ihrem Fall entfernen, um Ihre geschäftlichen Anforderungen zu erfüllen.

private fun isWorkEverScheduledBefore(context: Context, tag: String): Boolean {
    val instance = WorkManager.getInstance(context)
    val statuses: ListenableFuture<List<WorkInfo>> = instance.getWorkInfosForUniqueWork(tag)
    var workScheduled = false
    statuses.get()?.let {
        for (workStatus in it) {
            workScheduled = (
                        workStatus.state == WorkInfo.State.ENQUEUED
                                || workStatus.state == WorkInfo.State.RUNNING
                                || workStatus.state == WorkInfo.State.BLOCKED
                                || workStatus.state.isFinished // It checks SUCCEEDED, FAILED, CANCELLED already
                    )
        }
    }
    return workScheduled
}

1042730cookie-checkÜberprüfen Sie, ob WorkManager bereits eingeplant ist

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy