Definiowanie próśb o pracę

W przewodniku dla początkujących opisaliśmy, jak utworzyć proste WorkRequest. i umieść w kolejce.

Z tego przewodnika dowiesz się, jak definiować i dostosowywać obiekty WorkRequest dotyczące typowych przypadków użycia, na przykład:

  • Planowanie zadań jednorazowych i cyklicznych
  • określać ograniczenia pracy, np. wymagać Wi-Fi lub ładowania.
  • Zagwarantowanie minimalnego opóźnienia w realizacji zadań
  • Ustaw strategie ponawiania i wycofywania
  • Przekazywanie danych wejściowych do pracy
  • Grupuj powiązane działania za pomocą tagów

Omówienie

Praca jest określana w usłudze WorkManager za pomocą WorkRequest. Aby zaplanować pracę z usługą WorkManager. Najpierw trzeba utworzyć WorkRequest obiekt, a następnie umieść go w kolejce.

Kotlin

val myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest)

Java

WorkRequest myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest);

Obiekt WorkRequest zawiera wszystkie informacje potrzebne aplikacji WorkManager do planowanie i uruchamianie pracy. Obejmuje ograniczenia, które muszą być spełnione w przypadku prac do wykonania, informacje o harmonogramie, takie jak opóźnienia lub powtarzające się interwały, ponawianie próby konfiguracji i może uwzględniać dane wejściowe, jeśli są one wymagane w Twojej pracy.

Sama klasa WorkRequest jest abstrakcyjną klasą bazową. Dostępne są 2 implementacji pochodnej tej klasy, których możesz użyć do utworzenia żądania, OneTimeWorkRequest i PeriodicWorkRequest. OneTimeWorkRequest – jak sama nazwa wskazuje, jest przydatna do planowania materiały, które nie powtarzają się, natomiast PeriodicWorkRequest lepiej nadaje się do planowania zadań, które powtarzają się w określonych odstępach czasu.

Planowanie zadania jednorazowego

W przypadku prostych zadań, które nie wymagają dodatkowej konfiguracji, użyj statycznego parametru metoda from:

Kotlin

val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)

Java

WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);

W przypadku bardziej złożonych zadań możesz użyć kreatora:

Kotlin

val uploadWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilder<MyWork>()
       // Additional configuration
       .build()

Java

WorkRequest uploadWorkRequest =
   new OneTimeWorkRequest.Builder(MyWork.class)
       // Additional configuration
       .build();

Planowanie prac przyspieszonej

W aplikacji WorkManager 2.7.0 wprowadzono koncepcję przyspieszonej pracy. Dzięki temu WorkManager do wykonywania ważnych zadań, zapewniając jednocześnie większą kontrolę nad systemem i zwiększać dostęp do zasobów.

Przyspieszona praca wyróżnia się następującymi cechami:

  • Ważność: przyspieszona praca jest odpowiednia do zadań, które są ważne dla użytkownika lub są inicjowane przez użytkownika.
  • Szybkość: „szybka praca” najlepiej pasuje do krótkich zadań, które zaczynają się od razu. możesz zrobić to w ciągu kilku minut.
  • Limity: limit na poziomie systemu, który ogranicza czas wykonywania na pierwszym planie. określa, czy można uruchomić przyspieszone zadanie.
  • Zarządzanie zasilaniem: ograniczenia dotyczące zarządzania zasilaniem, np. Bateria. Oszczędzanie i uśpienie rzadziej wpływają na przyspieszoną pracę.
  • Czas oczekiwania: system natychmiast wykonuje przyspieszoną pracę, pod warunkiem że jest to możliwe w bieżącym zadaniu systemu. Oznacza to, że opóźnienia są poufne i nie można ich zaplanować do późniejszego wykonania.

Użycie przyspieszonej pracy może być np. w aplikacji do obsługi czatu, chce wysłać wiadomość lub załączony obraz. Podobnie aplikacja, która obsługuje w procesie płatności lub subskrypcji możesz też skorzystać z procesu przyspieszonego. To jest ponieważ są one ważne dla użytkownika, należy je szybko wykonać w tle, muszą rozpoczynać się natychmiast i powinny być nadal wykonywane nawet wtedy, użytkownik zamyka aplikację.

Limity

System musi przydzielić czas wykonywania do szybszego zadania, zanim może działać. Czas wykonywania nie jest nieograniczony. Każda aplikacja otrzymuje limit czas wykonywania. Gdy aplikacja wykorzysta czas wykonywania i osiągnie przydzielony limit, nie możesz wykonywać przyspieszonej pracy, dopóki limit odświeża się. Dzięki temu Android może efektywniej równoważyć zasoby aplikacji.

Czas wykonywania dostępny dla aplikacji zależy od zasobnik w trybie gotowości i znaczenie procesu.

Możesz określić, co się dzieje, gdy limit wykonania nie pozwala na zadanie przyspieszone do uruchomienia. Szczegóły znajdziesz w poniższych fragmentach kodu.

Wykonywanie prac przyspieszonych

Od wersji WorkManager 2.7 aplikacja może wywoływać metodę setExpedited(), aby zadeklarować, że zadanie WorkRequest powinno być uruchamiane jak najszybciej za pomocą zadania przyspieszonego. ten fragment kodu zawiera przykład użycia setExpedited():

Kotlin

val request = OneTimeWorkRequestBuilder<SyncWorker>()
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build()

WorkManager.getInstance(context)
    .enqueue(request)

Java

OneTimeWorkRequest request = new OneTimeWorkRequestBuilder<T>()
    .setInputData(inputData)
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build();

W tym przykładzie inicjujemy wystąpienie OneTimeWorkRequest i wywołujemy funkcję setExpedited(). To żądanie stanie się wówczas procesem przyspieszonym. Jeśli limit zacznie działać od razu w tle. Jeśli limit ma będzie używany, parametr OutOfQuotaPolicy wskazuje, że żądanie powinno przebiegać jak normalnie, bez przyspieszonego generowania.

Zgodność wsteczna i usługi na pierwszym planie

Aby zachować zgodność wsteczną na potrzeby przyspieszonego wykonywania zadań, WorkManager może uruchamiać usługi na pierwszym planie na platformach w wersjach starszych niż Android 12. Usługi działające na pierwszym planie mogą wyświetlać użytkownikowi powiadomienia.

Metody getForegroundInfoAsync() i getForegroundInfo() w instancji roboczej włącz w WorkManageru wyświetlanie powiadomień, gdy zadzwonisz do: setExpedited() przed Androidem 12.

Każdy element ListenableWorker musi implementować metodę getForegroundInfo, jeśli prosi o uruchomienie zadania jako zadania przyspieszonego.

W przypadku kierowania na Androida 12 lub nowszego usługi działające na pierwszym planie pozostają dostępne dla: za pomocą odpowiedniej metody setForeground.

Instancja robocza

Pracownicy nie wiedzą, czy ich praca przebiega szybciej, czy nie. Ale może wyświetlać powiadomienie w niektórych wersjach Androida, gdy WorkRequest została przyspieszona.

Aby to umożliwić, WorkManager udostępnia metodę getForegroundInfoAsync(), który musisz zaimplementować, aby usługa WorkManager mogła wyświetlać powiadomienie, by uruchomić ForegroundService.

Komponent roboczy Coroutine

Jeśli używasz metody CoroutineWorker, musisz zaimplementować getForegroundInfo(). Ty to przekaż ją usłudze setForeground() w ciągu doWork(). Spowoduje to utworzenie na urządzeniach z Androidem w wersji starszej niż 12.

Przyjrzyjmy się temu przykładowi:

  class ExpeditedWorker(appContext: Context, workerParams: WorkerParameters):
   CoroutineWorker(appContext, workerParams) {

   override suspend fun getForegroundInfo(): ForegroundInfo {
       return ForegroundInfo(
           NOTIFICATION_ID, createNotification()
       )
   }

   override suspend fun doWork(): Result {
       TODO()
   }

    private fun createNotification() : Notification {
       TODO()
    }

}

Zasady dotyczące limitów

Możesz określić, co ma się stać z pracą przyspieszoną, gdy aplikacja osiągnie limit wykonywania. Aby kontynuować, możesz mijać setExpedited():

  • OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST, który powoduje, że zadanie jak zwykłe żądanie pracy. Fragment kodu powyżej to potwierdza.
  • OutOfQuotaPolicy.DROP_WORK_REQUEST, co powoduje anulowanie żądania, jeśli nie ma wystarczającego limitu.

Przykładowa aplikacja

Pełny przykład wykorzystania przyspieszonej pracy w WorkManager 2.7.0 znajdziesz przy użyciu narzędzia WorkManagerSample na GitHubie.

Przyspieszona praca odroczona

System próbuje wykonać dane przyspieszone zadanie jak najszybciej po . Jednak, podobnie jak w przypadku innych rodzajów zadań, system może opóźnić rozpoczęcie nowych prac przyspieszonych, na przykład w następujących przypadkach:

  • Obciążenie: zbyt duże obciążenie systemu, co może wystąpić, gdy zostanie przestawiony zbyt wiele zadań. już uruchomionych lub gdy w systemie jest za mało pamięci.
  • Limit: limit przyspieszonego zadania został przekroczony. Praca przyspieszona wykorzystuje system limitów oparty na zasobnikach gotowości aplikacji i ogranicza maksymalny czas wykonywania w ruchomym oknie czasowym. Limity używane w: przyspieszonych czynności są bardziej restrykcyjne niż te używane w przypadku zadań w tle.

Planowanie zadań okresowych

Aplikacja może czasami wymagać okresowego wykonywania pewnych zadań. Przykład: warto od czasu do czasu tworzyć kopie zapasowe danych, pobierać nowe materiały i pobierać je lub przesyłanie dzienników na serwer.

Oto jak możesz użyć narzędzia PeriodicWorkRequest do utworzenia Obiekt WorkRequest, który jest okresowo uruchamiany:

Kotlin

val saveRequest =
       PeriodicWorkRequestBuilderS<aveImageToFileWorker(>1, TimeUnit.HOURS)
    // Additional configuration
           .build()

Java

PeriodicWorkRequest saveRequest =
       new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS)
           // Constraints
           .build();

W tym przykładzie zadanie jest zaplanowane z godzinnym odstępem.

Okres interwału to minimalny czas między powtórzeniami. dokładny czas wykonania instancji roboczej zależy od ograniczeń których używasz w obiekcie WorkRequest i podanych optymalizacji. przez system.

Elastyczne interwały biegów

Jeśli charakter Twojej pracy sprawia, że zależy Ci na synchronizacji czasu, możesz skonfigurować Twój PeriodicWorkRequest, aby biegać elastycznie okresu w każdym przedziale czasu, jak pokazano na rys. 1.

W przypadku zadania okresowego możesz ustawić interwał elastyczny. Określasz interwał powtarzania,
i przedział Flex, który określa określony czas na końcu
interwału powtórzenia. WorkManager próbuje uruchomić zadanie w pewnym momencie podczas
interwału elastycznego w każdym cyklu.

Rysunek 1. Diagram pokazuje powtarzające się interwały z okresem elastycznym w które można uruchomić.

Aby zdefiniować pracę okresową z okresem elastycznym, przekaż flexInterval wraz z parametrem repeatInterval podczas tworzenia PeriodicWorkRequest. Okres elastyczny zaczyna się o repeatInterval - flexInterval i kończy się na końcu interwału.

Oto przykład zadań okresowych, które mogą być wykonywane w ciągu ostatnich 15 lat min w każdej godzinie.

Kotlin

val myUploadWork = PeriodicWorkRequestBuilderS<aveImageToFileWorker(>
       1, TimeUnit.HOURS, // repeatInterval (the period cycle)
       15, TimeUnit.MINUTES) // flexInterval
    .build()

Java

WorkRequest saveRequest =
       new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class,
               1, TimeUnit.HOURS,
               15, TimeUnit.MINUTES)
           .build();

Interwał powtarzania nie może być mniejszy niż PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS i elastyczność interwał musi być większy niż lub równy PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS

Wpływ ograniczeń na pracę okresową

Do prac okresowych możesz stosować ograniczenia. Możesz na przykład dodać do żądania związanego z pracą, tak aby działała ona tylko wtedy, gdy urządzenie się ładuje. W tym przypadku, nawet jeśli zdefiniowany interwał powtarzania minie, PeriodicWorkRequest nie będzie działać, dopóki ten warunek nie zostanie spełniony. Może to spowodować opóźnienia konkretnego wykonania pracy lub nawet pominięcie go, jeśli nie są spełnione warunki w przedziale uruchomienia.

Ograniczenia pracy

Ograniczenia powodują odroczenie zadań do momentu spełnienia optymalnych warunków. W usłudze WorkManager dostępne są poniższe ograniczenia.

Typ sieci Ogranicza typ sieci wymagany do działania. Na przykład Wi-Fi (UNMETERED).
Niski poziom baterii Jeśli zasada ma wartość Prawda, praca nie będzie wykonywana, gdy urządzenie będzie działać w trybie niskiego poziomu baterii.
Wymaga ładowania Jeśli ma wartość Prawda, Twoja praca będzie wykonywana tylko podczas ładowania urządzenia.
Brak urządzenia Jeśli zasada ma wartość Prawda, urządzenie użytkownika jest nieaktywne, aby można było uruchomić pracę. Jest to przydatne przy przeprowadzaniu operacji zbiorczych, które w przeciwnym razie mogłyby mieć negatywny wpływ na wydajność innych aplikacji aktywnych aktywnie na urządzeniu użytkownika.
Mało miejsca na dane Jeśli zasada ma wartość Prawda, pliki nie są uruchamiane, jeśli na urządzeniu użytkownika jest za mało miejsca.

Aby utworzyć zbiór ograniczeń i powiązać go z jakąś pracą, utwórz instancję Constraints przy użyciu interfejsu Contraints.Builder() i przypisz ją do WorkRequest.Builder()

Na przykład ten kod tworzy żądanie robocze, które jest uruchamiane tylko wtedy, urządzenie użytkownika ładuje się i jest połączone z Wi-Fi:

Kotlin

val constraints = Constraints.Builder()
   .setRequiredNetworkType(NetworkType.UNMETERED)
   .setRequiresCharging(true)
   .build()

val myWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilderM<yWork(>)
       .setConstraints(constraints)
       .build()

Java

Constraints constraints = new Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresCharging(true)
       .build();

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
               .setConstraints(constraints)
               .build();

Jeśli określisz wiele ograniczeń, praca będzie wykonywana tylko wtedy, gdy wszystkie są spełnione ograniczenia.

Jeśli ograniczenie przestanie obowiązywać w trakcie pracy, WorkManager zatrzyma instancję roboczą. Zadanie zostanie ponowione, gdy wszystkie są spełnione ograniczenia.

Opóźniona praca

Jeśli praca nie ma ograniczeń lub wszystkie ograniczenia są po umieszczeniu zadania w kolejce system może je uruchomić natychmiast. Jeśli nie chcesz, aby zadanie było wykonywane natychmiast, możesz określić musisz zacząć pracę z minimalnym opóźnieniem.

Ten przykład pokazuje, jak ustawić czas pracy co najmniej 10 minut później został dodany do kolejki.

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilderM<yWork(>)
   .setInitialDelay(10, TimeUnit.MINUTES)
   .build()

Java

WorkRequest myWorkRequest =
      new OneTimeWorkRequest.Builder(MyWork.class)
               .setInitialDelay(10, TimeUnit.MINUTES)
               .build();

Chociaż ten przykład pokazuje, jak ustawić początkowe opóźnienie dla OneTimeWorkRequest, możesz też ustawić początkowe opóźnienie dla PeriodicWorkRequest W takim przypadku tylko pierwsze uruchomienie zadania okresowego miałoby miejsce z opóźnieniem.

Zasada ponawiania i wycofywania

Jeśli chcesz, aby usługa WorkManager ponownie wykonała zadanie, możesz zwrócić Result.retry() od Twojej instancji roboczej. W takim przypadku Twoja praca został przełożony zgodnie z opóźnieniem wycofywania i zasadami wycofywania.

  • Opóźnienie wycofania określa minimalny czas oczekiwania przed ponowną próbą. za pierwszym razem. Ta wartość nie może być mniejsza niż 10 sekund (lub MIN_BACKOFF_MILLIS).

  • Zasada ponawiania określa, jak opóźnienie do ponowienia powinno się zwiększać w przypadku kolejnych próbach. WorkManager obsługuje 2 zasady wycofywania: LINEAR i EXPONENTIAL

Każde żądanie pracy ma zasadę ponowienia i opóźnienia. Zasada domyślna jest EXPONENTIAL (opóźnienie wynosi 30 sekund, ale możesz to zmienić w konfiguracji żądania służbowego.

Oto przykład dostosowywania zasady opóźnienia ponowienia i zasady.

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilderM<yWork(>)
   .setBackoffCriteria(
       BackoffPolicy.LINEAR,
       OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
       TimeUnit.MILLISECONDS)
   .build()

Java

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
               .setBackoffCriteria(
                       BackoffPolicy.LINEAR,
                       OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                       TimeUnit.MILLISECONDS)
               .build();

W tym przykładzie minimalne opóźnienie do ponowienia jest ustawione na minimalną dopuszczalne wartości, 10 sekund. Ponieważ zasada ma wartość LINEAR, interwał ponawiania prób zwiększy się o około 10 sekund przy każdej nowej próbie. Na przykład pierwsze uruchomienie za pomocą polecenia Result.retry() zostanie ponowna próba nawiązania połączenia za 10 sekund, następnie następnie 20, 30, 40 itd., jeśli zadanie będzie nadal zwracać Result.retry() po kolejnych próbach. Jeśli zasada ponawiania była ustawiona na EXPONENTIAL, sekwencja czasu trwania ponawiania będzie bliższa wartości 20, 40, 80 itd. włącz.

Tag działa

Każde żądanie służbowe ma unikalny identyfikator, który umożliwia identyfikację które można wykonać później, aby anulować pracę lub obserwować jej postęp.

Jeśli masz grupę zadań powiązanych logicznie, przydatne może być również oznaczyć je tagami. Oznaczanie tagami pozwala pracować z grupą prac wszystkich żądań.

Na przykład WorkManager.cancelAllWorkByTag(String) anuluje wszystkie żądania robocze z określonym tagiem oraz WorkManager.getWorkInfosByTag(String) zwraca listę Obiekty WorkInfo, których można używać do określania bieżącego stanu pracy.

Ten kod pokazuje, jak dodać „czyszczenie” dodaj tagi do swojej pracy:

Kotlin

val myWorkRequest = OneTimeWorkRequestBuilderM<yWork(>)
   .addTag("cleanup")
   .build()

Java

WorkRequest myWorkRequest =
       new OneTimeWorkRequest.Builder(MyWork.class)
       .addTag("cleanup")
       .build();

Do jednego żądania roboczego można dodać wiele tagów. Wewnętrznie te są przechowywane jako zbiór ciągów znaków. Aby uzyskać zestaw tagów powiązanych z w WorkRequest możesz użyć WorkInfo.getTags().

Z klasy Worker możesz pobrać zestaw tagów za pomocą ListenableWorker.getTags().

Przypisz dane wejściowe

Twoja praca może wymagać danych wejściowych. Na przykład: uchwyty przesyłania obrazu mogą wymagać podania identyfikatora URI obrazu jako dane wejściowe.

Wartości wejściowe są przechowywane jako pary klucz-wartość w obiekcie Data i można je ustawić w zależności od zadania. WorkManager dostarczy dane wejściowe Data do podczas wykonywania pracy. Zajęcia w aplikacji Worker mają dostęp dla argumentów wejściowych przez wywołanie metody Worker.getInputData(). poniżej pokazuje, jak utworzyć instancję Worker, która wymaga danych wejściowych i sposobu ich przesyłania w żądaniu służbowym.

Kotlin

// Define the Worker requiring input
class UploadWork(appContext: Context, workerParams: WorkerParameters)
   : Worker(appContext, workerParams) {

   override fun doWork(): Result {
       val imageUriInput =
           inputData.getString("IMAGE_URI") ?: return Result.failure()

       uploadFile(imageUriInput)
       return Result.success()
   }
   ...
}

// Create a WorkRequest for your Worker and sending it input
val myUploadWork = OneTimeWorkRequestBuilderU<ploadWork(>)
   .setInputData(workDataOf(
       "IMAGE_URI" to "http://..."
   ))
   .build()

Java

// Define the Worker requiring input
public class UploadWork extends Worker {

   public UploadWork(Context appContext, WorkerParameters workerParams) {
       super(appContext, workerParams);
   }

   @NonNull
   @Override
   public Result doWork() {
       String imageUriInput = getInputData().getString("IMAGE_URI");
       if(imageUriInput == null) {
           return Result.failure();
       }

       uploadFile(imageUriInput);
       return Result.success();
   }
   ...
}

// Create a WorkRequest for your Worker and sending it input
WorkRequest myUploadWork =
      new OneTimeWorkRequest.Builder(UploadWork.class)
           .setInputData(
               new Data.Builder()
                   .putString("IMAGE_URI", "http://...")
                   .build()
           )
           .build();

Analogicznie klasy Data można użyć do wygenerowania zwracanej wartości. Dane wejściowe danych wyjściowych omówiono bardziej szczegółowo w sekcji Parametry wejściowe zwracanych wartości.

Dalsze kroki

Na stronie Stany i obserwacja znajdziesz więcej informacji o stanach pracy i monitorowanie postępów.