Android-Auftragsplaner

In diesem Leitfaden wird erläutert, wie Sie Hintergrundarbeiten mit der Android-Auftragsplanungs-API planen, die auf Android-Geräten mit Android 5.0 (API-Ebene 21) und höher verfügbar ist.

Übersicht

Eine der besten Möglichkeiten, um eine Android-Anwendung auf den Benutzer reagieren zu lassen, besteht darin, sicherzustellen, dass komplexe oder lang andauernde Arbeiten im Hintergrund ausgeführt werden. Es ist jedoch wichtig, dass sich Hintergrundarbeit nicht negativ auf die Benutzerfreundlichkeit mit dem Gerät auswirkt.

Beispielsweise kann ein Hintergrundauftrag alle drei oder vier Minuten eine Website abfragen, um Änderungen an einem bestimmten Dataset abzufragen. Dies scheint gut zu sein, hätte jedoch eine katastrophale Auswirkung auf die Akkulaufzeit. Die Anwendung wird das Gerät wiederholt reaktivieren, die CPU in einen höheren Leistungszustand versetzen, die Funkgeräte einschalten, netzwerkanforderungen stellen und dann die Ergebnisse verarbeiten. Es wird schlimmer, da das Gerät nicht sofort heruntergefahren wird und in den Leerlaufzustand mit geringer Leistung zurückkehrt. Schlecht geplante Hintergrundarbeit kann das Gerät versehentlich in einem Zustand mit unnötigen und übermäßigen Stromanforderungen halten. Diese scheinbar unschuldige Aktivität (Das Abrufen einer Website) wird das Gerät in relativ kurzer Zeit unbrauchbar machen.

Android stellt die folgenden APIs bereit, um die Ausführung von Arbeiten im Hintergrund zu unterstützen, aber sie allein reichen für eine intelligente Auftragsplanung nicht aus.

  • Absichtsdienste : Absichtsdienste eignen sich hervorragend für die Ausführung der Arbeit, bieten jedoch keine Möglichkeit, Die Arbeit zu planen.
  • AlarmManager : Diese APIs ermöglichen nur die Planung der Arbeit, bieten jedoch keine Möglichkeit, die Arbeit tatsächlich auszuführen. Außerdem lässt der AlarmManager nur zeitbasierte Einschränkungen zu, was bedeutet, dass ein Alarm zu einem bestimmten Zeitpunkt oder nach Ablauf eines bestimmten Zeitraums ausgelöst wird.
  • Broadcast Receivers : Eine Android-App kann Rundfunkempfänger einrichten, um Arbeiten als Reaktion auf systemweite Ereignisse oder Absichten auszuführen. Sendeempfänger bieten jedoch keine Kontrolle darüber, wann der Auftrag ausgeführt werden soll. Änderungen am Android-Betriebssystem schränken außerdem ein, wann Rundfunkempfänger funktionieren oder auf welche Arten von Aufgaben sie reagieren können.

Es gibt zwei wichtige Features für die effiziente Ausführung von Hintergrundarbeiten (manchmal auch als Hintergrundauftrag oder Auftrag bezeichnet):

  1. Intelligente Planung der Arbeit – Es ist wichtig, dass eine Anwendung, die im Hintergrund arbeitet, dies als guter Bürger tut. Im Idealfall sollte die Anwendung nicht verlangen, dass ein Auftrag ausgeführt wird. Stattdessen sollte die Anwendung Bedingungen angeben, die erfüllt werden müssen, wenn der Auftrag ausgeführt werden kann, und dann diesen Auftrag mit dem Betriebssystem planen, das die Arbeit ausführt, wenn die Bedingungen erfüllt sind. Dadurch kann Android den Auftrag ausführen, um eine maximale Effizienz auf dem Gerät zu gewährleisten. Netzwerkanforderungen können beispielsweise im Batch ausgeführt werden, um alle gleichzeitig auszuführen, um den mit dem Netzwerk verbundenen Mehraufwand maximal zu nutzen.
  2. Kapselung der Arbeit : Der Code zum Ausführen der Hintergrundarbeiten sollte in eine diskrete Komponente gekapselt werden, die unabhängig von der Benutzeroberfläche ausgeführt werden kann und relativ einfach neu geplant werden kann, wenn die Arbeit aus irgendeinem Grund nicht abgeschlossen werden kann.

Der Android-Auftragsplaner ist ein Framework, das in das Android-Betriebssystem integriert ist und eine Fluent-API bietet, um die Planung von Hintergrundarbeiten zu vereinfachen. Der Android-Auftragsplaner besteht aus den folgenden Typen:

  • Der Android.App.Job.JobScheduler ist ein Systemdienst, der zum Planen, Ausführen und ggf. Abbrechen von Aufträgen im Auftrag einer Android-Anwendung verwendet wird.
  • Ein Android.App.Job.JobService ist eine abstrakte Klasse, die mit der Logik erweitert werden muss, die den Auftrag im Standard Thread der Anwendung ausführen wird. Dies bedeutet, dass der JobService dafür verantwortlich ist, wie die Arbeit asynchron ausgeführt werden soll.
  • Ein Android.App.Job.JobInfo -Objekt enthält die Kriterien, die Android anleiten sollen, wann der Auftrag ausgeführt werden soll.

Um die Arbeit mit dem Android-Auftragsplaner zu planen, muss eine Xamarin.Android-Anwendung den Code in einer Klasse kapseln, die die JobService Klasse erweitert. JobService verfügt über drei Lebenszyklusmethoden, die während der Lebensdauer des Auftrags aufgerufen werden können:

  • bool OnStartJob(JobParameters parameters) – Diese Methode wird von aufgerufenJobScheduler, um Arbeiten auszuführen, und wird im Standard Thread der Anwendung ausgeführt. Es liegt in der Verantwortung des JobService , die Arbeit asynchron auszuführen und zurückzugeben true , wenn noch Arbeit vorhanden ist oder false wenn die Arbeit erledigt ist.

    Wenn diese JobScheduler Methode aufgerufen wird, wird ein Wakelock von Android für die Dauer des Auftrags gefordert und beibehalten. Wenn der Auftrag abgeschlossen ist, liegt es in der Verantwortung des JobService , den JobScheduler von dieser Tatsache zu informieren, indem sie die JobFinished -Methode aufrufen (weiter beschrieben).

  • JobFinished(JobParameters-Parameter, bool needsReschedule) – Diese Methode muss von JobService aufgerufen werden, um mitzuteilen JobScheduler , dass die Arbeit erledigt ist. Wenn JobFinished nicht aufgerufen wird, wird der JobScheduler Wakelock nicht entfernt, was zu unnötigem Akkuverbrauch führt.

  • bool OnStopJob(JobParameters-Parameter): Dies wird aufgerufen, wenn der Auftrag von Android vorzeitig beendet wird. Es sollte zurückgegeben true werden, wenn der Auftrag basierend auf den Wiederholungskriterien (unten ausführlicher erläutert) neu geplant werden soll.

Es ist möglich, Einschränkungen oder Trigger anzugeben, die steuern, wann ein Auftrag ausgeführt werden kann oder soll. Beispielsweise ist es möglich, einen Auftrag so einzuschränken, dass er nur ausgeführt wird, wenn das Gerät aufgeladen wird, oder um einen Auftrag zu starten, wenn ein Bild aufgenommen wird.

In diesem Leitfaden wird ausführlich erläutert, wie eine JobService Klasse implementiert und mit JobSchedulerdem geplant wird.

Anforderungen

Für den Android-Auftragsplaner ist die Android-API-Ebene 21 (Android 5.0) oder höher erforderlich.

Verwenden des Android-Auftragsplaner

Es gibt drei Schritte für die Verwendung der Android JobScheduler-API:

  1. Implementieren Sie einen JobService-Typ, um die Arbeit zu kapseln.
  2. Verwenden Sie ein JobInfo.Builder -Objekt, um das JobInfo -Objekt zu erstellen, das die Kriterien für die JobScheduler Ausführung des Auftrags enthält.
  3. Planen Sie den Auftrag mit JobScheduler.Schedule.

Implementieren eines JobService

Alle von der Android Job Scheduler-Bibliothek ausgeführten Arbeiten müssen in einem Typ ausgeführt werden, der die Android.App.Job.JobService abstrakte Klasse erweitert. Das Erstellen eines JobService ähnelt dem Erstellen eines Service mit dem Android-Framework:

  1. Erweitern Sie die JobService-Klasse.
  2. Dekorieren Sie die Unterklasse mit dem ServiceAttribute , und legen Sie den Name Parameter auf eine Zeichenfolge fest, die aus dem Paketnamen und dem Namen der Klasse besteht (siehe das folgende Beispiel).
  3. Legen Sie die Permission -Eigenschaft für auf ServiceAttribute die Zeichenfolge android.permission.BIND_JOB_SERVICEfest.
  4. Überschreiben Sie die OnStartJob -Methode, und fügen Sie den Code hinzu, um die Arbeit auszuführen. Android ruft diese Methode im Standard Thread der Anwendung auf, um den Auftrag auszuführen. Arbeit, die länger dauert, als einige Millisekunden für einen Thread ausgeführt werden sollten, um eine Blockierung der Anwendung zu vermeiden.
  5. Wenn die Arbeit erledigt ist, muss die JobService - JobFinished Methode aufgerufen werden. Mit dieser Methode wird JobService mitgeteilt, dass die JobScheduler Arbeit erledigt ist. Ein Nichtaufruf JobFinished führt JobService dazu, dass unnötige Anforderungen an das Gerät gestellt werden und die Akkulaufzeit verkürzt wird.
  6. Es empfiehlt sich, die OnStopJob Methode auch außer Kraft zu setzen. Diese Methode wird von Android aufgerufen, wenn der Auftrag heruntergefahren wird, bevor er abgeschlossen ist, und bietet die JobService Möglichkeit, alle Ressourcen ordnungsgemäß zu entsorgen. Diese Methode sollte zurückgegeben true werden, wenn der Auftrag neu geplant werden muss oder false wenn es nicht wünschenswert ist, den Auftrag erneut auszuführen.

Der folgende Code ist ein Beispiel für die einfachsten JobService für eine Anwendung, die die TPL zum asynchronen Ausführen von Aufgaben verwendet:

[Service(Name = "com.xamarin.samples.downloadscheduler.DownloadJob", 
         Permission = "android.permission.BIND_JOB_SERVICE")]
public class DownloadJob : JobService
{
    public override bool OnStartJob(JobParameters jobParams)
    {            
        Task.Run(() =>
        {
            // Work is happening asynchronously
                      
            // Have to tell the JobScheduler the work is done. 
            JobFinished(jobParams, false);
        });

        // Return true because of the asynchronous work
        return true;  
    }

    public override bool OnStopJob(JobParameters jobParams)
    {
        // we don't want to reschedule the job if it is stopped or cancelled.
        return false; 
    }
}

Erstellen einer JobInfo zum Planen eines Auftrags

Xamarin.Android-Anwendungen instanziieren nicht direkt, JobService sondern übergeben ein JobInfo -Objekt an die JobScheduler. Die JobScheduler instanziieren das angeforderte JobService Objekt, planen und ausführen den JobService entsprechend den Metadaten in der JobInfo. Ein JobInfo -Objekt muss die folgenden Informationen enthalten:

  • JobId : Dies ist ein int Wert, der verwendet wird, um einen Auftrag für zu JobScheduleridentifizieren. Durch die Wiederverwendung dieses Werts werden alle vorhandenen Aufträge aktualisiert. Der Wert muss für die Anwendung eindeutig sein.
  • JobService : Dieser Parameter identifiziert ComponentName explizit den Typ, der JobScheduler zum Ausführen eines Auftrags verwendet werden soll.

Mit dieser Erweiterungsmethode wird veranschaulicht, wie sie JobInfo.Builder mit einem Android-Gerät Contexterstellt werden, z. B. eine Aktivität:

public static class JobSchedulerHelpers
{
    public static JobInfo.Builder CreateJobBuilderUsingJobId<T>(this Context context, int jobId) where T:JobService
    {
        var javaClass = Java.Lang.Class.FromType(typeof(T));
        var componentName = new ComponentName(context, javaClass);
        return new JobInfo.Builder(jobId, componentName);
    }
}

// Sample usage - creates a JobBuilder for a DownloadJob and sets the Job ID to 1.
var jobBuilder = this.CreateJobBuilderUsingJobId<DownloadJob>(1);

var jobInfo = jobBuilder.Build();  // creates a JobInfo object.

Ein leistungsstarkes Feature des Android-Auftragsplaner ist die Möglichkeit zu steuern, wann ein Auftrag ausgeführt wird oder unter welchen Bedingungen ein Auftrag ausgeführt werden kann. In der folgenden Tabelle werden einige der Methoden JobInfo.Builder beschrieben, mit denen eine App beeinflussen kann, wann ein Auftrag ausgeführt werden kann:

Methode BESCHREIBUNG
SetMinimumLatency Gibt an, dass eine Verzögerung (in Millisekunden) beobachtet werden soll, bevor ein Auftrag ausgeführt wird.
SetOverridingDeadline Deklariert, dass der Auftrag ausgeführt werden muss, bevor diese Zeit (in Millisekunden) verstrichen ist.
SetRequiredNetworkType Gibt die Netzwerkanforderungen für einen Auftrag an.
SetRequiresBatteryNotLow Der Auftrag kann nur ausgeführt werden, wenn das Gerät dem Benutzer keine Warnung "Akkustand" anzeigt.
SetRequiresCharging Der Auftrag kann nur ausgeführt werden, wenn der Akku aufgeladen wird.
SetDeviceIdle Der Auftrag wird ausgeführt, wenn das Gerät ausgelastet ist.
SetPeriodic Gibt an, dass der Auftrag regelmäßig ausgeführt werden soll.
SetPersisted Der Auftrag sollte über Geräteneustarts hinweg ausgeführt werden.

Der SetBackoffCriteria enthält eine Anleitung dazu, wie lange die JobScheduler warten sollte, bevor sie versuchen, einen Auftrag erneut auszuführen. Es gibt zwei Teile der Backoffkriterien: eine Verzögerung in Millisekunden (Standardwert von 30 Sekunden) und den Typ des Backoffs, der verwendet werden soll (manchmal auch als Backoffrichtlinie oder Wiederholungsrichtlinie bezeichnet). Die beiden Richtlinien sind in der Android.App.Job.BackoffPolicy Aufzählung gekapselt:

  • BackoffPolicy.Exponential – Eine exponentielle Backoffrichtlinie erhöht den anfänglichen Backoffwert nach jedem Fehler exponentiell. Wenn ein Auftrag zum ersten Mal fehlschlägt, wartet die Bibliothek das angegebene anfangs angegebene Intervall, bevor der Auftrag neu geplant wird ( Beispiel 30 Sekunden). Wenn der Auftrag zum zweiten Mal fehlschlägt, wartet die Bibliothek mindestens 60 Sekunden, bevor sie versucht, den Auftrag auszuführen. Nach dem dritten fehlgeschlagenen Versuch wartet die Bibliothek 120 Sekunden usw. Dies ist der Standardwert.
  • BackoffPolicy.Linear – Diese Strategie ist ein linearer Backoff, bei dem der Auftrag neu geplant werden sollte, um in festgelegten Intervallen ausgeführt zu werden (bis er erfolgreich ist). Linearer Backoff eignet sich am besten für Arbeiten, die so schnell wie möglich abgeschlossen werden müssen, oder für Probleme, die sich schnell beheben lassen.

Weitere Informationen zum Erstellen eines JobInfo Objekts finden Sie in der Google-Dokumentation für die JobInfo.Builder Klasse.

Übergeben von Parametern an einen Auftrag über jobInfo

Parameter werden an einen Auftrag übergeben, indem ein PersistableBundle erstellt wird, das zusammen mit der Job.Builder.SetExtras -Methode übergeben wird:

var jobParameters = new PersistableBundle();
jobParameters.PutInt("LoopCount", 11);

var jobBuilder = this.CreateJobBuilderUsingJobId<DownloadJob>(1)
                     .SetExtras(jobParameters)
                     .Build();

Auf PersistableBundle wird über die Android.App.Job.JobParameters.Extras -Eigenschaft in der OnStartJob -Methode eines JobServicezugegriffen:

public override bool OnStartJob(JobParameters jobParameters)
{
    var loopCount = jobParams.Extras.GetInt("LoopCount", 10);
    
    // rest of code omitted
} 

Planen eines Auftrags

Um einen Auftrag zu planen, ruft eine Xamarin.Android-Anwendung einen Verweis auf den JobScheduler Systemdienst ab und ruft die Methode mit dem JobScheduler.ScheduleJobInfo Objekt auf, das im vorherigen Schritt erstellt wurde. JobScheduler.Schedule wird sofort mit einem von zwei ganzzahligen Werten zurückgegeben:

  • JobScheduler.ResultSuccess : Der Auftrag wurde erfolgreich geplant.
  • JobScheduler.ResultFailure : Der Auftrag konnte nicht geplant werden. Dies wird in der Regel durch in Konflikt stehende JobInfo Parameter verursacht.

Dieser Code ist ein Beispiel für die Planung eines Auftrags und die Benachrichtigung des Benutzers über die Ergebnisse des Planungsversuchs:

var jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
var scheduleResult = jobScheduler.Schedule(jobInfo);

if (JobScheduler.ResultSuccess == scheduleResult)
{
    var snackBar = Snackbar.Make(FindViewById(Android.Resource.Id.Content), Resource.String.jobscheduled_success, Snackbar.LengthShort);
    snackBar.Show();
}
else
{
    var snackBar = Snackbar.Make(FindViewById(Android.Resource.Id.Content), Resource.String.jobscheduled_failure, Snackbar.LengthShort);
    snackBar.Show();
}

Abbrechen eines Auftrags

Es ist möglich, alle geplanten Aufträge oder nur einen einzelnen Auftrag mit der JobsScheduler.CancelAll() -Methode oder der JobScheduler.Cancel(jobId) -Methode abzubrechen:

// Cancel all jobs
jobScheduler.CancelAll(); 

// to cancel a job with jobID = 1
jobScheduler.Cancel(1)

Zusammenfassung

In diesem Leitfaden wurde erläutert, wie Sie den Android-Auftragsplaner verwenden, um Arbeiten im Hintergrund intelligent auszuführen. Es wurde erläutert, wie sie die auszuführende JobService Arbeit kapseln und verwenden, um diese JobScheduler Arbeit zu planen, wobei die Kriterien mit einem JobTrigger angegeben werden und wie Fehler mit einem RetryStrategybehandelt werden sollen.