Ich verwende JobScheduler, um Jobs zu planen. Hauptsächlich verwende ich es für .setRequiredNetworkType()
-Methode, mit der Sie angeben können, dass der Auftrag nur dann geplant werden soll, wenn eine Netzwerkverbindung (oder genauer gesagt eine nicht gemessene Verbindung) hergestellt wird.
Ich verwende den folgenden ziemlich einfachen Code, um meine Jobs zu planen:
PersistableBundle extras = new PersistableBundle();
extras.putInt("anExtraInt", someInt);
int networkConstraint = useUnmetered ? JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
ComponentName componentName = new ComponentName(context, MyJobService.class);
JobInfo jobInfo = new JobInfo.Builder(jobId, componentName)
.setRequiredNetworkType(networkConstraint)
.setExtras(extras)
.build();
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobInfo);
Es gibt also nur eine Einschränkung für die Planung: eine Netzwerkverbindung (die „beliebig“ oder „nicht gemessen“ sein kann).
Kurzfassung der Frage
Wie lege ich eine maximale Verzögerung fest, bis alle Einschränkungen erfüllt sind und der Job tatsächlich ausgeführt wird, z. B. „Führen Sie den Job innerhalb von 2 Sekunden nach der Herstellung einer Netzwerkverbindung aus“?
Längere Version (mit Geschwafel)
Das Problem
Ich stelle fest, dass auf einigen Geräten ein Auftrag für einen Zeitraum geplant ist, in dem die Netzwerkbeschränkung besteht schon zufriedenwird der Job sofort ausgeführt (oder schnell genug, um vom Benutzer als solcher wahrgenommen zu werden).
Aber auf anderen Geräten kommt es, selbst wenn bereits eine geeignete Netzwerkverbindung vorhanden ist (so dass der Job sofort ausgeführt werden kann), zu einer erheblichen Verzögerung, bevor er tatsächlich ausgeführt wird. Erfolgt dies also als Reaktion auf eine Benutzeraktion, entsteht der Eindruck, dass nichts passiert ist und die App kaputt ist.
Nun, mir ist durchaus bewusst, dass dies wahrscheinlich die Absicht ist JobScheduler
… dass es Sache des Systems ist, den Job so zu planen, dass er am besten zu anderen Anforderungen passt, und dass es keine Garantie dafür gibt, dass der Job sofort ausgeführt wird, wenn alle Einschränkungen erfüllt sind.
Aber es wäre schön, wenn man es haben könnte manche Kontrolle darüber, sofern erforderlich. Für Aufgaben, die nach einem Zeitplan und ohne Eingreifen des Benutzers ausgeführt werden, ist es also in Ordnung und gut, dem System die vollständige Kontrolle über die genaue Zeitplanung zu geben.
Aber wenn der Job eine Reaktion auf eine Benutzeraktion ist, möchte ich, dass der Job ohne Verzögerung ausgeführt wird … vorausgesetzt, dass die Netzwerkverbindung vorhanden ist. (Wenn keine Verbindung besteht, kann eine Meldung angezeigt werden, dass die Aktion ausgeführt wird, wenn eine Netzwerkverbindung wiederhergestellt wird, und die JobScheduler
kümmert sich dann darum, dass der Job ausgeführt wird, wenn das Netzwerk wiederhergestellt ist.)
setOverrideDeadline() ist keine Lösung?
Ich kann sehen, dass JobInfo.Builder
hat ein setOverrideDeadline()
Methode, die fast das ist, was ich will. Aber das gibt die maximale Verzögerung an ab dem Zeitpunkt, an dem der Job geplant ist (dh den Job in 10 Sekunden ausführen, auch wenn nicht alle Einschränkungen erfüllt sind) und nicht ab dem Zeitpunkt, an dem alle Auflagen erfüllt sind (dh den Job innerhalb von 10 Sekunden ausführen, nachdem alle Einschränkungen erfüllt sind).
EDIT: Und es scheint einen lästigen Fehler zu geben, der dazu führen kann, dass der Job bei der Verwendung zweimal ausgeführt wird setOverrideDeadline()
: siehe hier und hier.
Was ist mit Firebase JobDispatcher?
Ich sehe das Firebase JobDispatcher hat ein Trigger.NOW
Abzug („bedeutet, dass der Job ausgeführt werden soll, sobald seine Laufzeitbeschränkungen erfüllt sind“). Vielleicht ist das der richtige Weg, wenn JobScheduler
unterstützt dies nicht nativ? Ich bin von Firebase JobDispatcher abgeschreckt worden, weil es so aussieht, als würde es einen Vorschlaghammer benutzen, um eine Nuss zu knacken … und es scheint, dass es bei Firebase nur um Cloud-Messaging usw. geht, was sehr weit von der lokalen Aufgabenplanung entfernt ist (was eine sein sollte). rein lokales Anliegen). Und es scheint Google Play-Dienste zu erfordern, was wiederum für die lokale Aufgabenplanung völlig unnötig erscheint. Darüber hinaus ist eine sofortige Auslösung mit Firebase möglich, und Firebase nutzt es einfach JobScheduler
für Android L+, dann muss es sicher möglich sein, dies direkt damit zu tun JobScheduler
ohne auf Firebase angewiesen zu sein?
EDIT: Ich habe das jetzt ausprobiert und sogar Trigger.NOW
garantiert keine sofortige Antwort … Tatsächlich stelle ich fest, dass es auf meinem Gerät eine Verzögerung von fast genau 30 Sekunden gibt, was seltsam ist.
Gelingt das nicht…
Die einzige Möglichkeit, die ich derzeit sehe, um eine sofortige Ausführung sicherzustellen (sofern die Einschränkungen erfüllt sind), besteht darin, Folgendes zu tun: nicht verwenden JobScheduler
.
Oder führen Sie die anfängliche Einschränkungsprüfung manuell durch und führen Sie den Job mit einem aus setOverrideDeadline()
von 0, wenn alle Einschränkungen erfüllt sind, andernfalls wird es ohne ausgeführt setOverrideDeadline()
.
Es wäre weitaus vorzuziehen, einfach nur die Möglichkeit zu haben, das Timing zu kontrollieren JobScheduler
selbst, ein bisschen wie man es mit dem kann setWindow()
Methode von AlarmManager
.
@OP, könnten Sie Ihren Beitrag bitte in kleinere Unterkategorien einteilen, in denen dargelegt wird, was Sie in Bezug auf das Problem, das Sie beheben möchten, sagen möchten?
– JoxTraex
8. September 2016 um 8:00 Uhr
@JoxTraex Das hatte ich bereits versucht (Kurzversion vs. Langversion), aber ich habe jetzt mehr Unterstruktur hinzugefügt. Niemand muss über die Kurzversion hinaus lesen, aber die Langversion bietet mehr Hintergrundinformationen.
– drmrbrewer
8. September 2016 um 8:42
Wie Sie angedeutet haben, vermute ich, dass dieser Mangel an API beabsichtigt ist. Sie können natürlich gerne danach fragen, ob es sich um eine Funktionserweiterung handelt, allerdings würde eine solche Erweiterung (vermutlich) bestenfalls erst bei Android O auftauchen, was bedeutet, dass es 2022 dauern wird, bis eine solche Funktion alltäglich wird. „Vielleicht führen Sie die anfängliche Einschränkungsprüfung manuell durch und führen den Job mit einem setOverrideDeadline() von 0 aus, wenn alle Einschränkungen erfüllt sind, andernfalls führen Sie ihn ohne setOverrideDeadline() aus“ – oder erledigen Sie einfach die Arbeit, wenn die Einschränkungen erfüllt sind, und überspringen Sie die Arbeit. Es macht keinen Sinn, es zu verwenden
JobScheduler
für die sofortige Arbeit.– CommonsWare
10. September 2016 um 20:17 Uhr
Also @CommonsWare, wenn ich eine habe
JobService
Gibt es eine Möglichkeit, dies direkt und nicht über a auszuführen?JobScheduler
wenn ich möchte, dass es einfach läuft Jetzt? Ich hasse es, Code zu duplizieren und einen separaten zu erstellenService
denn das scheint (selbst mit gemeinsam genutzten Funktionen) unelegant zu sein … viel ordentlicher, nur um damit anzufangenJobService
direkt?– drmrbrewer
10. September 2016 um 21:08 Uhr
„Wenn ich möchte, dass es jetzt einfach läuft?“ – AFAIK, Sie können anrufen
startService()
alleinJobService
. Refaktorieren Sie die tatsächlich zu erledigende Arbeit in einer separaten Klasse (für Ihren Hintergrundthread), die daraus erstellt und verwendet werden kannonStartJob()
oder vonstartService()
. Es sieht nicht so aus, als ob Sie ein erstellen könnenJobParameters
dich selbst, also kannst du es nicht habenstartService()
ForderungonStartJob()
es sei denn, Sie haben bestandennull
für dieJobParameters
.– CommonsWare
10. September 2016 um 21:12 Uhr