Udostępnij za pośrednictwem


Dyspozytor zadań rozwiązania Firebase

W tym przewodniku omówiono sposób planowania pracy w tle przy użyciu biblioteki Firebase Job Dispatcher firmy Google.

Omówienie

Jednym z najlepszych sposobów reagowania aplikacji systemu Android na użytkownika jest zapewnienie, że złożone lub długotrwałe prace są wykonywane w tle. Jednak ważne jest, aby praca w tle nie wpływała negatywnie na środowisko użytkownika z urządzeniem.

Na przykład zadanie w tle może sondować witrynę internetową co trzy lub cztery minuty, aby wykonać zapytanie o zmiany w określonym zestawie danych. Wydaje się to łagodne, jednak miałoby to katastrofalny wpływ na żywotność baterii. Aplikacja będzie wielokrotnie wznawiać urządzenie, podnieść poziom procesora CPU do wyższego stanu zasilania, włączyć urządzenia radiowe, wysyłać żądania sieciowe, a następnie przetwarzać wyniki. Pogarsza się, ponieważ urządzenie nie będzie natychmiast zasilać i wracać do stanu bezczynności o niskiej mocy. Nieprawidłowo zaplanowane prace w tle mogą przypadkowo zachować urządzenie w stanie z niepotrzebnymi i nadmiernymi wymaganiami dotyczącymi zasilania. Ta pozornie niewinna aktywność (sondowanie witryny internetowej) sprawi, że urządzenie będzie bezużyteczne w stosunkowo krótkim czasie.

System Android udostępnia następujące interfejsy API, które ułatwiają wykonywanie pracy w tle, ale same w sobie nie są wystarczające do inteligentnego planowania zadań.

  • Intent Services — usługi Intent Services doskonale nadają się do wykonywania pracy, ale nie zapewniają możliwości planowania pracy.
  • AlarmManager — te interfejsy API zezwalają tylko na zaplanowanie pracy, ale nie zapewniają możliwości rzeczywistego wykonania pracy. Ponadto menedżer alarmów zezwala tylko na ograniczenia oparte na czasie, co oznacza zgłaszanie alarmu w określonym czasie lub po upływie określonego czasu.
  • JobScheduler — usługa JobSchedule to doskonały interfejs API, który współdziała z systemem operacyjnym w celu planowania zadań. Jednak jest ona dostępna tylko dla tych aplikacji systemu Android, które są przeznaczone dla interfejsu API na poziomie 21 lub wyższym.
  • Odbiorniki rozgłaszań — aplikacja systemu Android może skonfigurować odbiorniki emisji w celu wykonywania pracy w odpowiedzi na zdarzenia lub intencje dla całego systemu. Jednak odbiorniki emisji nie zapewniają żadnej kontroli nad tym, kiedy zadanie powinno zostać uruchomione. Zmiany w systemie operacyjnym Android będą również ograniczać, gdy odbiorniki emisji będą działać lub rodzaje pracy, na które mogą reagować.

Istnieją dwie kluczowe funkcje wydajnego wykonywania pracy w tle (czasami określane jako zadanie w tle lub zadanie):

  1. Inteligentne planowanie pracy — ważne jest, aby aplikacja wykonywała pracę w tle, co robi jako dobry obywatel. Najlepiej, aby aplikacja nie wymagała uruchomienia zadania. Zamiast tego aplikacja powinna określać warunki, które muszą zostać spełnione, gdy zadanie może zostać uruchomione, a następnie zaplanować pracę do uruchomienia po spełnieniu warunków. Dzięki temu system Android może inteligentnie wykonywać pracę. Na przykład żądania sieciowe mogą być wsadowe do uruchamiania wszystkich w tym samym czasie, aby maksymalnie wykorzystać obciążenie związane z siecią.
  2. Hermetyzowanie pracy — kod do wykonania pracy w tle powinien być hermetyzowany w dyskretnym składniku, który można uruchomić niezależnie od interfejsu użytkownika i będzie stosunkowo łatwy do ponownego przygotowania, jeśli praca nie zostanie ukończona z jakiegoś powodu.

Dyspozytor zadań Firebase to biblioteka firmy Google, która zapewnia płynny interfejs API, aby uprościć planowanie pracy w tle. Jest on przeznaczony do zastąpienia usługi Google Cloud Manager. Dyspozytor zadań Firebase składa się z następujących interfejsów API:

  • A Firebase.JobDispatcher.JobService to abstrakcyjna klasa, która musi zostać rozszerzona o logikę, która będzie uruchamiana w zadaniu w tle.
  • Element Firebase.JobDispatcher.JobTrigger deklaruje, kiedy zadanie powinno zostać uruchomione. Zwykle jest to wyrażone jako przedział czasu, na przykład poczekaj co najmniej 30 sekund przed uruchomieniem zadania, ale uruchom zadanie w ciągu 5 minut.
  • Element Firebase.JobDispatcher.RetryStrategy zawiera informacje o tym, co należy wykonać, gdy zadanie nie powiedzie się prawidłowo. Strategia ponawiania prób określa czas oczekiwania przed ponownym uruchomieniem zadania.
  • Jest Firebase.JobDispatcher.Constraint to opcjonalna wartość, która opisuje warunek, który musi zostać spełniony przed uruchomieniem zadania, takiego jak urządzenie, znajduje się w niemetrycznej sieci lub ładowaniu.
  • Jest Firebase.JobDispatcher.Job to interfejs API, który łączy poprzednie interfejsy API z jednostką pracy, którą można zaplanować za pomocą polecenia JobDispatcher. Klasa Job.Builder służy do tworzenia wystąpienia klasy Job.
  • Funkcja Firebase.JobDispatcher.JobDispatcher używa poprzednich trzech interfejsów API do planowania pracy z systemem operacyjnym i zapewnienia sposobu anulowania zadań, jeśli jest to konieczne.

Aby zaplanować pracę z dyspozytorem zadań Firebase, aplikacja platformy Xamarin.Android musi hermetyzować kod w typie rozszerzającym klasę JobService . JobService ma trzy metody cyklu życia, które mogą być wywoływane w okresie istnienia zadania:

  • bool OnStartJob(IJobParameters parameters) — Ta metoda polega na tym, że nastąpi praca i zawsze powinna zostać wdrożona. Działa on w głównym wątku. Ta metoda zwróci wartość true , jeśli pozostała praca lub false czy praca zostanie wykonana.
  • bool OnStopJob(IJobParameters parameters) — Jest to wywoływane, gdy zadanie zostanie zatrzymane z jakiegoś powodu. Powinno ono zostać zwrócone true , jeśli zadanie powinno zostać ponownie ułożone na później.
  • JobFinished(IJobParameters parameters, bool needsReschedule) — Ta metoda jest wywoływana po zakończeniu JobService dowolnej pracy asynchronicznej.

Aby zaplanować zadanie, aplikacja utworzy wystąpienie JobDispatcher obiektu. Job.Builder Następnie element jest używany do utworzenia Job obiektu, który jest dostarczany do JobDispatcher polecenia , który spróbuje zaplanować uruchomienie zadania.

W tym przewodniku omówiono sposób dodawania dyspozytora zadań firebase do aplikacji platformy Xamarin.Android i używania jej do planowania pracy w tle.

Wymagania

Dyspozytor zadań Firebase wymaga interfejsu API systemu Android na poziomie 9 lub wyższym. Biblioteka Dyspozytora zadań Firebase opiera się na niektórych składnikach udostępnianych przez usługi Google Play; urządzenie musi mieć zainstalowane usługi Google Play.

Korzystanie z biblioteki dyspozytora zadań Firebase w środowisku Xamarin.Android

Aby rozpocząć pracę z dyspozytorem zadań Firebase, najpierw dodaj pakiet NuGet Xamarin.Firebase.JobDispatcher do projektu Xamarin.Android. Wyszukaj Menedżer pakietów NuGet dla pakietu Xamarin.Firebase.JobDispatcher (który jest nadal w wersji wstępnej).

Po dodaniu biblioteki Firebase Job Dispatcher utwórz klasę JobService , a następnie zaplanuj jej uruchomienie przy użyciu wystąpienia klasy FirebaseJobDispatcher.

Tworzenie usługi zadań

Wszystkie prace wykonywane przez bibliotekę Dyspozytora zadań firebase muszą być wykonywane w typie rozszerzającym klasę abstrakcyjną Firebase.JobDispatcher.JobService . Tworzenie elementu JobService jest bardzo podobne do tworzenia za Service pomocą platformy systemu Android:

  1. Rozszerzanie JobService klasy
  2. Udekoruj podklasę za pomocą klasy ServiceAttribute. Chociaż nie jest to ściśle wymagane, zaleca się jawne ustawienie parametru Name w celu ułatwienia debugowania elementu JobService.
  3. Dodaj element , IntentFilter aby zadeklarować element JobService w AndroidManifest.xml. Pomoże to również w zlokalizowaniu i wywołaniu biblioteki dyspozytora zadań firebase i wywołaniu polecenia JobService.

Poniższy kod jest przykładem najprostszego JobService dla aplikacji, używając języka TPL do asynchronicznego wykonywania pewnych zadań:

[Service(Name = "com.xamarin.fjdtestapp.DemoJob")]
[IntentFilter(new[] {FirebaseJobServiceIntent.Action})]
public class DemoJob : JobService
{
    static readonly string TAG = "X:DemoService";

    public override bool OnStartJob(IJobParameters jobParameters)
    {
        Task.Run(() =>
        {
            // Work is happening asynchronously (code omitted)
                       
        });

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

    public override bool OnStopJob(IJobParameters jobParameters)
    {
        Log.Debug(TAG, "DemoJob::OnStartJob");
        // nothing to do.
        return false;
    }
}

Tworzenie bazy danych FirebaseJobDispatcher

Zanim będzie można zaplanować pracę, należy utworzyć Firebase.JobDispatcher.FirebaseJobDispatcher obiekt. Jest FirebaseJobDispatcher odpowiedzialny za zaplanowanie elementu JobService. Poniższy fragment kodu jest jednym ze sposobów utworzenia wystąpienia elementu FirebaseJobDispatcher:

// This is the "Java" way to create a FirebaseJobDispatcher object
IDriver driver = new GooglePlayDriver(context);
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(driver);

W poprzednim fragmencie kodu jest to klasa, GooglePlayDriver która ułatwia interakcję FirebaseJobDispatcher z niektórymi interfejsami API planowania w usługach Google Play na urządzeniu. Parametr context jest dowolnym systemem Android Context, takim jak działanie. GooglePlayDriver Obecnie jest jedyną implementacją IDriver w bibliotece Firebase Job Dispatcher.

Powiązanie platformy Xamarin.Android dla dyspozytora zadań firebase udostępnia metodę rozszerzenia umożliwiającą FirebaseJobDispatcher utworzenie elementu na podstawie elementu Context:

FirebaseJobDispatcher dispatcher = context.CreateJobDispatcher();

Po utworzeniu FirebaseJobDispatcher wystąpienia obiektu można utworzyć Job i uruchomić kod w JobService klasie . Obiekt Job jest tworzony przez Job.Builder obiekt i zostanie omówiony w następnej sekcji.

Tworzenie pliku Firebase.JobDispatcher.Job za pomocą narzędzia Job.Builder

Klasa Firebase.JobDispatcher.Job jest odpowiedzialna za hermetyzowanie metadanych niezbędnych do uruchomienia klasy JobService. ElementJob zawiera informacje, takie jak wszelkie ograniczenia, które muszą zostać spełnione przed uruchomieniem zadania, jeśli Job element jest cykliczny lub wyzwalacze, które spowodują uruchomienie zadania. Jako minimum Job musi mieć tag (unikatowy ciąg, który identyfikuje zadanie w FirebaseJobDispatcherobiekcie ) i typ JobService , który powinien zostać uruchomiony. Dyspozytor zadań Firebase utworzy wystąpienie JobService , gdy jest czas uruchamiania zadania. Element A Job jest tworzony przy użyciu wystąpienia Firebase.JobDispatcher.Job.JobBuilder klasy .

Poniższy fragment kodu to najprostszy przykład tworzenia Job powiązania platformy Xamarin.Android:

Job myJob = dispatcher.NewJobBuilder()
                      .SetService<DemoJob>("demo-job-tag")
                      .Build();

Spowoduje to Job.Builder przeprowadzenie pewnych podstawowych kontroli poprawności dla wartości wejściowych zadania. Wyjątek zostanie zgłoszony, jeśli nie będzie możliwe Job.Builder utworzenie elementu Job. Spowoduje to Job.Builder utworzenie elementu Job z następującymi wartościami domyślnymi:

  • JobOkres istnienia (jak długo zostanie zaplanowany do uruchomienia) jest tylko do momentu ponownego uruchomienia urządzenia — po ponownym uruchomieniu Job urządzenia zostanie utracone.
  • Element nie Job jest cykliczny — zostanie uruchomiony tylko raz.
  • Harmonogram Job zostanie zaplanowany tak szybko, jak to możliwe.
  • Domyślną strategią ponawiania prób dla elementu Job jest użycie wycofywania wykładniczego (omówiono bardziej szczegółowo poniżej w sekcji Ustawianie strategii ponawiania)

Planowanie zadań

Po utworzeniu Jobelementu należy zaplanować go z parametrem FirebaseJobDispatcher przed jego uruchomieniem. Istnieją dwie metody planowania elementu Job:

// This will throw an exception if there was a problem scheduling the job
dispatcher.MustSchedule(myJob);

// This method will not throw an exception; an integer result value is returned
int scheduleResult = dispatcher.Schedule(myJob);

Wartość zwrócona przez FirebaseJobDispatcher.Schedule będzie jedną z następujących wartości całkowitych:

  • FirebaseJobDispatcher.ScheduleResultSuccess – Plan Job został pomyślnie zaplanowany.
  • FirebaseJobDispatcher.ScheduleResultUnknownError — Wystąpił nieznany problem, który uniemożliwił zaplanowanie Job .
  • FirebaseJobDispatcher.ScheduleResultNoDriverAvailable – Użyto nieprawidłowego IDriverIDriver elementu lub był w jakiś sposób niedostępny.
  • FirebaseJobDispatcher.ScheduleResultUnsupportedTrigger – Nie Trigger było obsługiwane.
  • FirebaseJobDispatcher.ScheduleResultBadService — Usługa nie jest poprawnie skonfigurowana lub jest niedostępna.

Konfigurowanie zadania

Istnieje możliwość dostosowania zadania. Przykłady dostosowywania zadania obejmują następujące elementy:

Każdy z tych tematów zostanie omówiony bardziej w poniższych sekcjach.

Przekazywanie parametrów do zadania

Parametry są przekazywane do zadania przez utworzenie przekazanego Job.Builder.SetExtras elementu Bundle wraz z metodą :

Bundle jobParameters = new Bundle();
jobParameters.PutInt(FibonacciCalculatorJob.FibonacciPositionKey, 25);

Job myJob = dispatcher.NewJobBuilder()
                      .SetService<DemoJob>("demo-job-tag")
                      .SetExtras(jobParameters)
                      .Build();

Dostęp Bundle do obiektu jest uzyskiwany z IJobParameters.Extras właściwości w metodzie OnStartJob :

public override bool OnStartJob(IJobParameters jobParameters)
{
    int position = jobParameters.Extras.GetInt(FibonacciPositionKey, DEFAULT_VALUE);
    
    // rest of code omitted
} 

Ustawianie ograniczeń

Ograniczenia mogą pomóc zmniejszyć koszty lub opróżnienie baterii na urządzeniu. Klasa Firebase.JobDispatcher.Constraint definiuje te ograniczenia jako wartości całkowite:

  • Constraint.OnUnmeteredNetwork — Uruchamiaj zadanie tylko wtedy, gdy urządzenie jest połączone z niemetryczną siecią. Jest to przydatne, aby uniemożliwić użytkownikowi naliczanie opłat za dane.
  • Constraint.OnAnyNetwork — Uruchom zadanie w dowolnej sieci, z jaką urządzenie jest połączone. Jeśli określono wartość wraz z parametrem Constraint.OnUnmeteredNetwork, ta wartość będzie mieć priorytet.
  • Constraint.DeviceCharging — Uruchom zadanie tylko wtedy, gdy urządzenie jest ładowane.

Ograniczenia są ustawiane przy użyciu Job.Builder.SetConstraint metody :

Job myJob = dispatcher.NewJobBuilder()
                      .SetService<DemoJob>("demo-job-tag")
                      .SetConstraint(Constraint.DeviceCharging)
                      .Build();

Zawiera JobTrigger wskazówki dotyczące systemu operacyjnego o tym, kiedy zadanie powinno zostać uruchomione. Element JobTrigger ma okno wykonywania, które definiuje zaplanowany czas uruchamiania Job . Okno wykonywania ma wartość okna uruchamiania i wartość okna końcowego. Okno uruchamiania to liczba sekund oczekiwania urządzenia przed uruchomieniem zadania, a wartość okna końcowego to maksymalna liczba sekund oczekiwania przed uruchomieniem Job.

Element JobTrigger można utworzyć za Firebase.Jobdispatcher.Trigger.ExecutionWindow pomocą metody . Na przykład Trigger.ExecutionWindow(15,60) oznacza, że zadanie powinno działać z zakresu od 15 do 60 sekund od momentu zaplanowanego. Metoda Job.Builder.SetTrigger jest używana do

JobTrigger myTrigger = Trigger.ExecutionWindow(15,60);
Job myJob = dispatcher.NewJobBuilder()
                      .SetService<DemoJob>("demo-job-tag")
                      .SetTrigger(myTrigger)
                      .Build();

Wartość domyślna JobTrigger zadania jest reprezentowana przez wartość Trigger.Now, która określa, że zadanie jest uruchamiane tak szybko, jak to możliwe po zaplanowaniu.

Ustawianie strategii ponawiania

Służy Firebase.JobDispatcher.RetryStrategy do określania, ile opóźnienia urządzenie powinno używać przed próbą ponownego uruchomienia zadania, które zakończyło się niepowodzeniem. Element RetryStrategy ma zasady, które określają, jaki algorytm bazy czasowej będzie używany do ponownego planowania zadania, które zakończyło się niepowodzeniem, oraz okno wykonywania określające okno, w którym zadanie powinno zostać zaplanowane. To okno zmiany jest definiowane przez dwie wartości. Pierwsza wartość to liczba sekund oczekiwania przed ponownym zaplanowaniem zadania ( początkowa wartość wycofywania ), a druga liczba to maksymalna liczba sekund przed uruchomieniem zadania ( maksymalna wartość wycofywania ).

Dwa typy zasad ponawiania prób są identyfikowane przez następujące wartości int:

  • RetryStrategy.RetryPolicyExponential— Zasady wycofywania wykładniczego zwiększą początkową wartość wycofywania wykładniczo po każdym niepowodzeniu. Podczas pierwszego niepowodzenia zadania biblioteka będzie czekać _initial interwał określony przed ponownym zaplanowaniem zadania — na przykład 30 sekund. Po raz drugi zadanie zakończy się niepowodzeniem, biblioteka będzie czekać co najmniej 60 sekund przed próbą uruchomienia zadania. Po trzeciej nieudanej próbie biblioteka będzie czekać 120 sekund itd. Wartość domyślna RetryStrategy dla biblioteki Firebase Job Dispatcher jest reprezentowana RetryStrategy.DefaultExponential przez obiekt . Ma początkowe wycofywanie wynoszące 30 sekund i maksymalną backoff wynoszącą 3600 sekund.
  • RetryStrategy.RetryPolicyLinear— Ta strategia jest liniowym wycofywaniem, które powinno zostać ponownie zaplanowane, aby zadanie było uruchamiane w ustalonych odstępach czasu (dopóki nie powiedzie się). Wycofywanie liniowe najlepiej nadaje się do pracy, która musi zostać ukończona tak szybko, jak to możliwe lub w przypadku problemów, które szybko się rozwiążą. Biblioteka dyspozytora zadań programu Firebase definiuje RetryStrategy.DefaultLinear bibliotekę, która ma okno ponownego trwania co najmniej 30 sekund i maksymalnie 3600 sekund.

Istnieje możliwość zdefiniowania niestandardowego RetryStrategy przy użyciu FirebaseJobDispatcher.NewRetryStrategy metody . Przyjmuje trzy parametry:

  1. int policy— Zasada jest jedną z poprzednich RetryStrategy wartości, RetryStrategy.RetryPolicyLinear, lub RetryStrategy.RetryPolicyExponential.
  2. int initialBackoffSeconds — Początkowe wycofywanie jest opóźnieniem w sekundach, które jest wymagane przed ponownym uruchomieniem zadania. Wartość domyślna dla tej wartości to 30 sekund.
  3. int maximumBackoffSeconds— Maksymalna wartość wycofywania deklaruje maksymalną liczbę sekund opóźnienia przed ponownym uruchomieniem zadania. Wartość domyślna to 3600 sekund.
RetryStrategy retry = dispatcher.NewRetryStrategy(RetryStrategy.RetryPolicyLinear, initialBackoffSeconds, maximumBackoffSet);

// Create a Job and set the RetryStrategy via the Job.Builder
Job myJob = dispatcher.NewJobBuilder()
                      .SetService<DemoJob>("demo-job-tag")
                      .SetRetryStrategy(retry)
                      .Build();

Anulowanie zadania

Istnieje możliwość anulowania wszystkich zaplanowanych zadań lub tylko jednego zadania przy użyciu FirebaseJobDispatcher.CancelAll() metody lub FirebaseJobDispatcher.Cancel(string) metody:

int cancelResult = dispatcher.CancelAll(); 

// to cancel a single job:

int cancelResult = dispatcher.Cancel("unique-tag-for-job");

Każda z metod zwróci wartość całkowitą:

  • FirebaseJobDispatcher.CancelResultSuccess — Zadanie zostało pomyślnie anulowane.
  • FirebaseJobDispatcher.CancelResultUnknownError — Błąd uniemożliwiał anulowanie zadania.
  • FirebaseJobDispatcher.CancelResult.NoDriverAvailable — Nie FirebaseJobDispatcher można anulować zadania, ponieważ nie ma prawidłowej IDriver dostępności.

Podsumowanie

W tym przewodniku omówiono sposób użycia dyspozytora zadań Firebase do inteligentnego wykonywania pracy w tle. Omówiono w nim sposób hermetyzacji pracy, która ma być wykonywana jako element JobService i jak używać FirebaseJobDispatcher elementu do planowania tej pracy, określając kryteria za pomocą elementu JobTrigger oraz sposób obsługi błędów za pomocą elementu RetryStrategy.