Ten moduł Codelab jest częścią kursu Android Kotlin Fundamentals. Najwięcej korzyści przyniesie Ci ukończenie wszystkich ćwiczeń w kolejności. Wszystkie ćwiczenia z tego kursu znajdziesz na stronie docelowej kursu Android Kotlin Fundamentals.
Wprowadzenie
Większość aplikacji w rzeczywistym świecie musi wykonywać długotrwałe zadania w tle. Na przykład aplikacja może przesyłać pliki na serwer, synchronizować dane z serwera i zapisywać je w Roombazie danych, wysyłać dzienniki na serwer lub wykonywać złożone operacje na danych. Takie operacje powinny być wykonywane w tle, poza wątkiem interfejsu (wątkiem głównym). Zadania w tle zużywają ograniczone zasoby urządzenia, takie jak pamięć RAM i bateria. Jeśli nie zostanie to odpowiednio obsłużone, może negatywnie wpłynąć na wygodę użytkowników.
Z tego modułu dowiesz się, jak używać WorkManager do planowania zadań w tle w zoptymalizowany i wydajny sposób. Więcej informacji o innych dostępnych rozwiązaniach do przetwarzania w tle na Androidzie znajdziesz w przewodniku po przetwarzaniu w tle.
Co warto wiedzieć
- Jak korzystać z komponentów architektury Androida ViewModel,LiveDataiRoom.
- Jak przeprowadzać przekształcenia w klasie LiveData.
- Jak utworzyć i uruchomić korutynę.
- Jak używać adapterów powiązań w powiązaniu danych.
- Jak wczytywać dane z pamięci podręcznej za pomocą wzorca repozytorium.
Czego się nauczysz
- Jak utworzyć Worker, czyli jednostkę pracy.
- Jak utworzyć WorkRequest, aby poprosić o wykonanie pracy.
- Jak dodać ograniczenia do elementu WorkRequest, aby określić, jak i kiedy ma działać pracownik.
- Jak używać WorkManagerdo planowania zadań w tle.
Jakie zadania wykonasz
- Utwórz proces roboczy, który będzie wykonywać zadanie w tle polegające na wstępnym pobieraniu z sieci playlisty filmów DevBytes.
- Zaplanuj okresowe uruchamianie instancji roboczej.
- Dodaj ograniczenia do WorkRequest.
- Zaplanuj okresowe WorkRequest, które będzie wykonywane raz dziennie.
W tym ćwiczeniu z programowania będziesz pracować nad aplikacją DevBytes, którą utworzono w poprzednim ćwiczeniu. (Jeśli nie masz tej aplikacji, możesz pobrać kod początkowy do tej lekcji).
Aplikacja DevBytes wyświetla listę filmów DevByte, czyli krótkich samouczków przygotowanych przez zespół ds. relacji z deweloperami Androida w Google. Filmy te przedstawiają funkcje dla programistów i sprawdzone metody tworzenia aplikacji na Androida.
Ulepszasz wrażenia użytkowników w aplikacji, wstępnie pobierając filmy raz dziennie. Dzięki temu użytkownik zobaczy aktualne treści od razu po otwarciu aplikacji.

W tym zadaniu pobierzesz i sprawdzisz kod startowy.
Krok 1. Pobierz i uruchom aplikację startową
Możesz kontynuować pracę nad aplikacją DevBytes, którą utworzono w poprzednim laboratorium (jeśli ją masz). Możesz też pobrać aplikację startową.
W tym zadaniu pobierzesz i uruchomisz aplikację startową oraz sprawdzisz kod początkowy.
- Jeśli nie masz jeszcze aplikacji DevBytes, pobierz kod początkowy DevBytes do tego laboratorium z kodu z projektu DevBytesRepository w GitHubie.
- Rozpakuj kod i otwórz projekt w Android Studio.
- Połącz urządzenie testowe lub emulator z internetem, jeśli nie jest jeszcze połączone. Skompiluj i uruchom aplikację. Aplikacja pobierze z sieci listę filmów DevByte i wyświetli je.
- W aplikacji kliknij dowolny film, aby otworzyć go w aplikacji YouTube.
Krok 2. Zapoznaj się z kodem
Aplikacja początkowa zawiera dużo kodu, który został wprowadzony w poprzednim ćwiczeniu. Kod początkowy do tych ćwiczeń z programowania zawiera moduły sieciowe, interfejsu użytkownika, pamięci podręcznej offline i repozytorium. Możesz skupić się na planowaniu zadania w tle za pomocą funkcji WorkManager. 
- W Android Studio rozwiń wszystkie pakiety.
- Zapoznaj się z pakietem database. Pakiet zawiera jednostki bazy danych i lokalną bazę danych, która jest zaimplementowana przy użyciuRoom.
- Zapoznaj się z pakietem repository. Pakiet zawiera klasęVideosRepository, która oddziela warstwę danych od reszty aplikacji.
- Pozostałą część kodu początkowego możesz sprawdzić samodzielnie, korzystając z pomocy poprzedniego laboratorium.
WorkManager jest jednym ze składników architektury Androida i częścią Androida Jetpack. WorkManager – w przypadku zadań w tle, które można odłożyć i które wymagają gwarantowanego wykonania:
- Odroczenie oznacza, że zadanie nie musi być wykonane natychmiast. Na przykład wysyłanie danych analitycznych na serwer lub synchronizowanie bazy danych w tle to działania, które można odłożyć w czasie.
- Gwarantowane wykonanie oznacza, że zadanie zostanie wykonane nawet wtedy, gdy aplikacja zostanie zamknięta lub urządzenie zostanie ponownie uruchomione.

Gdy WorkManager działa w tle, rozwiązuje problemy z kompatybilnością i stosuje sprawdzone metody dotyczące baterii i stanu systemu. WorkManager jest zgodny z poziomem API 14. WorkManager wybiera odpowiedni sposób planowania zadania w tle w zależności od poziomu interfejsu API urządzenia. Może używać JobScheduler (w przypadku interfejsu API w wersji 23 i nowszych) lub kombinacji AlarmManager i BroadcastReceiver.
WorkManager umożliwia też ustawienie kryteriów, kiedy zadanie w tle ma być uruchamiane. Możesz na przykład chcieć, aby zadanie było wykonywane tylko wtedy, gdy stan baterii, stan sieci lub stan ładowania spełniają określone kryteria. W dalszej części tego modułu dowiesz się, jak ustawiać ograniczenia.
W tym ćwiczeniu w Codelabs zaplanujesz zadanie, które będzie codziennie pobierać z sieci listę odtwarzania filmów DevBytes. Aby zaplanować to zadanie, użyj biblioteki WorkManager.
- Otwórz plik build.gradle (Module:app)i dodaj do projektu zależnośćWorkManager.
 Jeśli używasz najnowszej wersji biblioteki, aplikacja z rozwiązaniem powinna się skompilować zgodnie z oczekiwaniami. Jeśli nie, spróbuj rozwiązać problem lub wróć do wersji biblioteki podanej poniżej.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"- Zsynchronizuj projekt i upewnij się, że nie ma błędów kompilacji.
Zanim dodasz kod do projektu, zapoznaj się z tymi klasami w bibliotece WorkManager:
- Worker
 W tej klasie definiujesz rzeczywistą pracę (zadanie), która ma być wykonywana w tle. Rozszerzasz tę klasę i zastępujesz metodę- doWork(). Metoda- doWork()to miejsce, w którym umieszczasz kod do wykonania w tle, np. synchronizację danych z serwerem lub przetwarzanie obrazów. W tym zadaniu wdrażasz- Worker.
- WorkRequest
 Ta klasa reprezentuje prośbę o uruchomienie procesu roboczego w tle. Użyj- WorkRequest, aby skonfigurować sposób i czas uruchamiania zadania roboczego za pomocą- Constraints, takich jak podłączenie urządzenia do zasilania lub połączenie z Wi-Fi.- WorkRequestzaimplementujesz w późniejszym zadaniu.
- WorkManager
 Ta klasa planuje i uruchamia- WorkRequest.- WorkManagerplanuje żądania pracy w taki sposób, aby rozłożyć obciążenie zasobów systemowych, przy jednoczesnym uwzględnieniu określonych przez Ciebie ograniczeń.- WorkManagerzaimplementujesz w późniejszym zadaniu.
Krok 1. Utwórz pracownika
W tym zadaniu dodasz element Worker, aby wstępnie pobrać w tle playlistę filmów DevBytes.
- W pakiecie devbyteviewerutwórz nowy pakiet o nazwiework.
- W pakiecie workutwórz nową klasę Kotlin o nazwieRefreshDataWorker.
- Rozszerz klasę RefreshDataWorkerz klasyCoroutineWorker. PrzekażcontextiWorkerParametersjako parametry konstruktora.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}- Aby rozwiązać błąd klasy abstrakcyjnej, zastąp metodę doWork()w klasieRefreshDataWorker.
override suspend fun doWork(): Result {
  return Result.success()
}Funkcja zawieszająca to funkcja, którą można wstrzymać i wznowić później. Funkcja zawieszająca może wykonywać długotrwałą operację i czekać na jej zakończenie bez blokowania wątku głównego.
Krok 2. Zaimplementuj funkcję doWork()
Metoda doWork() w klasie Worker jest wywoływana w wątku w tle. Metoda wykonuje pracę synchronicznie i powinna zwracać obiekt ListenableWorker.Result. System Android daje Worker maksymalnie 10 minut na zakończenie wykonywania i zwrócenie obiektu ListenableWorker.Result. Po upływie tego czasu system wymusza zatrzymanie Worker.
Aby utworzyć obiekt ListenableWorker.Result, wywołaj jedną z tych metod statycznych, aby wskazać stan ukończenia pracy w tle:
- Result.success()– praca została wykonana.
- Result.failure()– zadanie zostało ukończone z trwałą awarią.
- Result.retry()– zadanie napotkało przejściowy problem i należy ponowić próbę jego wykonania.
W tym zadaniu zaimplementujesz metodę doWork(), aby pobrać z sieci playlistę filmów DevBytes. Możesz ponownie wykorzystać istniejące metody w klasie VideosRepository, aby pobrać dane z sieci.
- W klasie RefreshDataWorkerwewnątrzdoWork()utwórz i zainicjuj obiektVideosDatabaseoraz obiektVideosRepository.
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)
   return Result.success()
}- W klasie RefreshDataWorker, wewnątrzdoWork(), nad instrukcjąreturnwywołaj metodęrefreshVideos()w blokutry. Dodaj log, aby śledzić, kiedy instancja robocza jest uruchamiana.
try {
   repository.refreshVideos( )
   Timber.d("Work request for sync is run")
   } catch (e: HttpException) {
   return Result.retry()
}Aby rozwiązać błąd „Unresolved reference” (Nierozwiązane odwołanie), zaimportuj retrofit2.HttpException.
- Oto pełna klasa RefreshDataWorker:
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
   override suspend fun doWork(): Result {
       val database = getDatabase(applicationContext)
       val repository = VideosRepository(database)
       try {
           repository.refreshVideos()
       } catch (e: HttpException) {
           return Result.retry()
       }
       return Result.success()
   }
}Worker definiuje jednostkę pracy, a WorkRequest określa, jak i kiedy należy wykonać pracę. Istnieją 2 konkretne implementacje klasy WorkRequest: 
- Klasa OneTimeWorkRequestjest przeznaczona do zadań jednorazowych. (Jednorazowe zadanie jest wykonywane tylko raz).
- Klasa PeriodicWorkRequestjest przeznaczona do pracy okresowej, która powtarza się w określonych odstępach czasu.
Zadania mogą być jednorazowe lub okresowe, więc wybierz odpowiednie zajęcia. Więcej informacji o planowaniu powtarzających się zadań znajdziesz w dokumentacji dotyczącej powtarzających się zadań.
W tym zadaniu zdefiniujesz i zaplanujesz WorkRequest, aby uruchomić proces roboczy utworzony w poprzednim zadaniu. 
Krok 1. Skonfiguruj powtarzające się zadania
W aplikacji na Androida klasa Application jest klasą bazową, która zawiera wszystkie inne komponenty, takie jak aktywności i usługi. Gdy proces dotyczący aplikacji lub pakietu zostanie utworzony, klasa Application (lub dowolna podklasa klasy Application) jest tworzona przed każdą inną klasą.
W tej przykładowej aplikacji klasa DevByteApplication jest podklasą klasy Application. DevByteApplication zajęcia to dobre miejsce na zaplanowanie WorkManager.
- W klasie DevByteApplicationutwórz metodę o nazwiesetupRecurringWork(), aby skonfigurować cykliczne zadanie w tle.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}- W metodzie setupRecurringWork()utwórz i zainicjuj okresowe żądanie pracy, które będzie wykonywane raz dziennie, używając metodyPeriodicWorkRequestBuilder(). Przekaż klasęRefreshDataWorkerutworzoną w poprzednim zadaniu. Przekaż interwał powtarzania1z jednostką czasuTimeUnit.DAYS.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .build()Aby rozwiązać ten problem, zaimportuj java.util.concurrent.TimeUnit.
Krok 2. Zaplanuj WorkRequest za pomocą WorkManager
Po zdefiniowaniu WorkRequest możesz zaplanować ją za pomocą WorkManager, używając metody enqueueUniquePeriodicWork(). Ta metoda umożliwia dodanie do kolejki unikalnie nazwanego elementu PeriodicWorkRequest, przy czym w danym momencie może być aktywny tylko jeden element PeriodicWorkRequest o określonej nazwie.
Możesz na przykład chcieć, aby aktywna była tylko jedna operacja synchronizacji. Jeśli oczekuje na wykonanie jedna operacja synchronizacji, możesz zezwolić na jej wykonanie lub zastąpić ją nową pracą, używając ExistingPeriodicWorkPolicy.
Więcej informacji o sposobach planowania WorkRequest znajdziesz w dokumentacji WorkManager.
- W klasie RefreshDataWorkerna początku klasy dodaj obiekt towarzyszący. Określ nazwę pracownika, aby jednoznacznie go zidentyfikować.
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}- W klasie DevByteApplicationna końcu metodysetupRecurringWork()zaplanuj pracę za pomocą metodyenqueueUniquePeriodicWork(). Przekaż enumKEEPdla ExistingPeriodicWorkPolicy. PrzekażrepeatingRequestjako parametrPeriodicWorkRequest.
WorkManager.getInstance().enqueueUniquePeriodicWork(
       RefreshDataWorker.WORK_NAME,
       ExistingPeriodicWorkPolicy.KEEP,
       repeatingRequest)Jeśli istnieje oczekująca (nieukończona) praca o tej samej nazwie, parametr ExistingPeriodicWorkPolicy.KEEP sprawia, że WorkManager zachowuje poprzednią pracę okresową i odrzuca nowe żądanie pracy.
- Na początku klasy DevByteApplicationutwórz obiektCoroutineScope. PrzekażDispatchers.Defaultjako parametr konstruktora.
private val applicationScope = CoroutineScope(Dispatchers.Default)- W klasie DevByteApplicationdodaj nową metodę o nazwiedelayedInit(), aby uruchomić korutynę.
private fun delayedInit() {
   applicationScope.launch {
   }
}- W metodzie delayedInit()wywołaj metodęsetupRecurringWork().
- Przenieś inicjowanie Timber z metody onCreate()do metodydelayedInit().
private fun delayedInit() {
   applicationScope.launch {
       Timber.plant(Timber.DebugTree())
       setupRecurringWork()
   }
}- W klasie DevByteApplicationna końcu metodyonCreate()dodaj wywołanie metodydelayedInit().
override fun onCreate() {
   super.onCreate()
   delayedInit()
}- Otwórz panel Logcat u dołu okna Android Studio. Filtruj według: RefreshDataWorker.
- Uruchom aplikację. WorkManagernatychmiast zaplanuje Twoją cykliczną pracę.
 W panelu Logcat zwróć uwagę na instrukcje logowania, które pokazują, że żądanie wykonania zostało zaplanowane, a następnie wykonane.
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
WM-WorkerWrapper log jest wyświetlany z WorkManager biblioteki, więc nie możesz zmienić tego komunikatu.
Krok 3. (Opcjonalnie) Zaplanuj WorkRequest na minimalny interwał
W tym kroku zmniejszysz przedział czasu z 1 dnia do 15 minut. Dzięki temu możesz zobaczyć logi okresowego żądania pracy w działaniu.
- W klasie DevByteApplicationw metodziesetupRecurringWork()zakomentuj bieżącą definicjęrepeatingRequest. Dodaj nową prośbę o wykonanie pracy z okresowym interwałem powtarzania wynoszącym15minut.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()- Otwórz panel Logcat w Android Studio i filtruj według RefreshDataWorker. Aby wyczyścić poprzednie dzienniki, kliknij ikonę Wyczyść Logcat . .
- Uruchom aplikację, a WorkManagerod razu zaplanuje Twoją cykliczną pracę. W panelu Logcat zwróć uwagę na dzienniki – żądanie pracy jest uruchamiane co 15 minut. Poczekaj 15 minut, aby zobaczyć kolejny zestaw logów żądań pracy. Możesz pozostawić aplikację uruchomioną lub ją zamknąć. Menedżer zadań powinien nadal działać.
 Zwróć uwagę, że interwał jest czasami krótszy niż 15 minut, a czasami dłuższy. (Dokładny czas zależy od optymalizacji baterii w systemie operacyjnym).
12:44:40 D/RefreshDataWorker: Work request for sync is run 12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 12:59:24 D/RefreshDataWorker: Work request for sync is run 12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:15:03 D/RefreshDataWorker: Work request for sync is run 13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:29:22 D/RefreshDataWorker: Work request for sync is run 13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:44:26 D/RefreshDataWorker: Work request for sync is run 13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
 Gratulacje! Utworzono pracownika i zaplanowano prośbę o wykonanie pracy w usłudze WorkManager. Ale jest problem: nie podano żadnych ograniczeń. WorkManager zaplanuje pracę raz dziennie, nawet jeśli bateria urządzenia jest słaba, urządzenie jest w trybie uśpienia lub nie ma połączenia z siecią. Wpłynie to na baterię i wydajność urządzenia oraz może pogorszyć wygodę użytkowników.
W kolejnym zadaniu rozwiążesz ten problem, dodając ograniczenia.
W poprzednim zadaniu użyto ikony WorkManager do zaplanowania prośby o wykonanie pracy. W tym zadaniu dodasz kryteria określające, kiedy ma być wykonywana praca.
Podczas definiowania WorkRequest możesz określić ograniczenia dotyczące tego, kiedy Worker ma być uruchamiana. Możesz na przykład określić, że zadanie ma być wykonywane tylko wtedy, gdy urządzenie jest nieaktywne lub gdy jest podłączone do zasilania i połączone z Wi-Fi. Możesz też określić zasady wycofywania, aby ponawiać wykonywanie zadań. Obsługiwane ograniczenia to metody ustawione w Constraints.Builder. Więcej informacji znajdziesz w artykule Określanie próśb o wykonanie pracy.
Krok 1. Dodaj obiekt Constraints i ustaw jedno ograniczenie
W tym kroku utworzysz obiekt Constraints i ustawisz na nim jedno ograniczenie – ograniczenie typu sieci. (Łatwiej jest zauważyć logi z tylko jednym ograniczeniem. W dalszej części dodasz inne ograniczenia).
- W klasie DevByteApplicationna początkusetupRecurringWork()zdefiniujvaltypuConstraints. Użyj metodyConstraints.Builder().
val constraints = Constraints.Builder()Aby rozwiązać ten problem, zaimportuj androidx.work.Constraints.
- Użyj metody setRequiredNetworkType(), aby dodać do obiektuconstraintsograniczenie typu sieć. Użyj wyliczeniaUNMETERED, aby żądanie pracy było wykonywane tylko wtedy, gdy urządzenie jest połączone z siecią bez limitu danych.
.setRequiredNetworkType(NetworkType.UNMETERED)- Użyj metody build(), aby wygenerować ograniczenia z konstruktora.
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .build()Teraz musisz ustawić nowo utworzony obiekt Constraints w żądaniu pracy.
- W klasie DevByteApplicationw metodziesetupRecurringWork()ustaw obiektConstraintsna okresowe żądanie wykonania zadaniarepeatingRequest. Aby ustawić ograniczenia, dodaj metodęsetConstraints()nad wywołaniem metodybuild().
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()Krok 2. Uruchom aplikację i zwróć uwagę na dzienniki
W tym kroku uruchomisz aplikację i zauważysz, że ograniczone żądanie pracy jest uruchamiane w tle w określonych odstępach czasu.
- Aby anulować wcześniej zaplanowane zadania, odinstaluj aplikację z urządzenia lub emulatora.
- Otwórz panel Logcat w Android Studio. W panelu Logcat wyczyść poprzednie logi, klikając ikonę Wyczyść Logcat  po lewej stronie. Filtruj według: po lewej stronie. Filtruj według:work.
- Wyłącz Wi-Fi na urządzeniu lub emulatorze, aby zobaczyć, jak działają ograniczenia. Obecny kod ustawia tylko jedno ograniczenie, które wskazuje, że żądanie powinno być uruchamiane tylko w sieci bez limitu danych. Wi-Fi jest wyłączone, więc urządzenie nie jest połączone z siecią (ani z siecią rozliczaną, ani z siecią nierozliczaną). Dlatego to ograniczenie nie zostanie spełnione.
- Uruchom aplikację i zwróć uwagę na panel Logcat. Usługa WorkManagernatychmiast planuje zadanie w tle. Zadanie nie zostanie uruchomione, ponieważ nie spełnia ograniczeń sieciowych.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
- Włącz Wi-Fi na urządzeniu lub emulatorze i obserwuj panel Logcat. Zaplanowane zadanie w tle jest teraz uruchamiane co około 15 minut, o ile spełnione jest ograniczenie dotyczące sieci.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled 11:31:47 D/RefreshDataWorker: Work request for sync is run 11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 11:46:45 D/RefreshDataWorker: Work request for sync is run 11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:03:05 D/RefreshDataWorker: Work request for sync is run 12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:16:45 D/RefreshDataWorker: Work request for sync is run 12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:31:45 D/RefreshDataWorker: Work request for sync is run 12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:47:05 D/RefreshDataWorker: Work request for sync is run 12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 13:01:45 D/RefreshDataWorker: Work request for sync is run 13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
Krok 3. Dodaj więcej ograniczeń
W tym kroku dodasz do pliku PeriodicWorkRequest te ograniczenia: 
- Bateria nie jest słaba.
- ładowanie urządzenia,
- Urządzenie jest nieaktywne; dostępne tylko na poziomie interfejsu API 23 (Android M) i nowszym.
Zaimplementuj w klasie DevByteApplication te elementy:
- W klasie DevByteApplicationw metodziesetupRecurringWork()wskaż, że żądanie pracy powinno być uruchamiane tylko wtedy, gdy poziom baterii nie jest niski. Dodaj ograniczenie przed wywołaniem metodybuild()i użyj metodysetRequiresBatteryNotLow().
.setRequiresBatteryNotLow(true)- Zaktualizuj żądanie pracy, aby było wykonywane tylko wtedy, gdy urządzenie jest ładowane. Dodaj ograniczenie przed wywołaniem metody build()i użyj metodysetRequiresCharging().
.setRequiresCharging(true)- Zaktualizuj żądanie pracy, aby było wykonywane tylko wtedy, gdy urządzenie jest bezczynne. Dodaj ograniczenie przed wywołaniem metody build()i użyj metodysetRequiresDeviceIdle(). To ograniczenie powoduje uruchomienie żądania pracy tylko wtedy, gdy użytkownik nie używa aktywnie urządzenia. Ta funkcja jest dostępna tylko na Androidzie 6.0 (Marshmallow) i nowszym, więc dodaj warunek dla wersji pakietu SDKMlub nowszej.
.apply {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
       setRequiresDeviceIdle(true)
   }
}Oto pełna definicja obiektu constraints.
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresBatteryNotLow(true)
       .setRequiresCharging(true)
       .apply {
           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
               setRequiresDeviceIdle(true)
           }
       }
       .build()- W metodzie setupRecurringWork()zmień interwał żądania z powrotem na raz dziennie.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .setConstraints(constraints)
       .build()Oto pełna implementacja metody setupRecurringWork() wraz z dziennikiem, który umożliwia śledzenie, kiedy zaplanowano okresowe żądanie wykonania zadania. 
private fun setupRecurringWork() {
       val constraints = Constraints.Builder()
               .setRequiredNetworkType(NetworkType.UNMETERED)
               .setRequiresBatteryNotLow(true)
               .setRequiresCharging(true)
               .apply {
                   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                       setRequiresDeviceIdle(true)
                   }
               }
               .build()
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
               .setConstraints(constraints)
               .build()
       
       Timber.d("Periodic Work request for sync is scheduled")
       WorkManager.getInstance().enqueueUniquePeriodicWork(
               RefreshDataWorker.WORK_NAME,
               ExistingPeriodicWorkPolicy.KEEP,
               repeatingRequest)
   }- Aby usunąć wcześniej zaplanowaną prośbę o wykonanie pracy, odinstaluj aplikację DevBytes z urządzenia lub emulatora.
- Uruchom aplikację, a WorkManagernatychmiast zaplanuje prośbę o wykonanie zadania. Żądanie pracy jest wykonywane raz dziennie, gdy zostaną spełnione wszystkie ograniczenia.
- To żądanie będzie działać w tle, dopóki aplikacja jest zainstalowana, nawet jeśli nie jest uruchomiona. Z tego powodu należy odinstalować aplikację z telefonu.
Doskonale! W aplikacji DevBytes zaimplementowano i zaplanowano przyjazne dla baterii żądanie pracy dotyczące codziennego wstępnego pobierania filmów. WorkManager zaplanuje i wykona pracę, optymalizując zasoby systemu. Twoi użytkownicy i ich baterie będą bardzo zadowoleni.
Projekt Android Studio: DevBytesWorkManager.
- Interfejs WorkManagerAPI ułatwia planowanie odroczonych zadań asynchronicznych, które muszą być wykonywane niezawodnie.
- Większość aplikacji w rzeczywistym świecie musi wykonywać długotrwałe zadania w tle. Aby zaplanować zadanie w tle w zoptymalizowany i wydajny sposób, użyj WorkManager.
- Główne klasy w bibliotece WorkManagertoWorker,WorkRequestiWorkManager.
- Klasa Workerreprezentuje jednostkę pracy. Aby zaimplementować zadanie w tle, rozszerz klasęWorkeri zastąp metodędoWork().
- Klasa WorkRequestreprezentuje prośbę o wykonanie jednostki pracy.WorkRequestto klasa bazowa do określania parametrów pracy, którą planujesz wWorkManager.
- Klasa WorkRequestma 2 konkretne implementacje:OneTimeWorkRequestw przypadku jednorazowych zadań iPeriodicWorkRequestw przypadku okresowych żądań pracy.
- Podczas definiowania WorkRequestmożesz określićConstraints, aby wskazać, kiedy ma się uruchamiaćWorker. Ograniczenia obejmują m.in. to, czy urządzenie jest podłączone do zasilania, czy jest w stanie bezczynności oraz czy jest połączone z Wi-Fi.
- Aby dodać ograniczenia do elementu WorkRequest, użyj metod ustawiania wymienionych w dokumentacjiConstraints.Builder. Jeśli na przykład chcesz wskazać, żeWorkRequestnie powinien działać, gdy bateria urządzenia jest bliska rozładowania, użyj metodysetRequiresBatteryNotLow().
- Po zdefiniowaniu WorkRequestprzekaż zadanie do systemu Android. Aby to zrobić, zaplanuj zadanie za pomocą jednej zWorkManagerenqueuemetod.
- Dokładny czas wykonania Workerzależy od ograniczeń użytych wWorkRequesti od optymalizacji systemu.WorkManagerma zapewniać najlepsze możliwe działanie w ramach tych ograniczeń.
Kurs Udacity:
Dokumentacja dla deweloperów aplikacji na Androida:
- Określanie próśb o wykonanie pracy
- WorkManager
- Pierwsze kroki z WorkManagerem
- Praca cykliczna
- Przewodnik po przetwarzaniu w tle
Inne:
W tej sekcji znajdziesz listę możliwych zadań domowych dla uczniów, którzy wykonują ten moduł w ramach kursu prowadzonego przez instruktora. Nauczyciel musi:
- W razie potrzeby przypisz pracę domową.
- Poinformuj uczniów, jak przesyłać projekty.
- Oceń zadania domowe.
Instruktorzy mogą korzystać z tych sugestii w dowolnym zakresie i mogą zadawać inne zadania domowe, które uznają za odpowiednie.
Jeśli wykonujesz ten kurs samodzielnie, możesz użyć tych zadań domowych, aby sprawdzić swoją wiedzę.
Pytanie 1
Jakie są konkretne implementacje klasy WorkRequest? 
▢ OneTimeWorkPeriodicRequest
▢ OneTimeWorkRequest i PeriodicWorkRequest
▢ OneTimeWorkRequest i RecurringWorkRequest
▢ OneTimeOffWorkRequest i RecurringWorkRequest
Pytanie 2
Której z poniższych klas używa WorkManager do planowania zadania w tle na poziomie API 23 i wyższym? 
▢ Tylko JobScheduler
▢ BroadcastReceiver i AlarmManager
▢ AlarmManager i JobScheduler
▢ Scheduler i BroadcastReceiver
Pytanie 3
Którego interfejsu API używasz, aby dodać ograniczenia do WorkRequest? 
▢ setConstraints()
▢ addConstraints()
▢ setConstraint()
▢ addConstraintsToWorkRequest()
Przejdź do następnej lekcji: 
Linki do innych ćwiczeń z tego kursu znajdziesz na stronie docelowej ćwiczeń z podstaw języka Kotlin na Androidzie.