Эта практическая работа входит в курс «Основы Android Kotlin». Вы получите максимальную пользу от этого курса, если будете выполнять практические работы последовательно. Все практические работы курса перечислены на целевой странице практической работы «Основы Android Kotlin» .
Введение
 Большинству реальных приложений необходимо выполнять длительные фоновые задачи. Например, приложение может загружать файлы на сервер, синхронизировать данные с сервера и сохранять их в базе данных Room , отправлять журналы на сервер или выполнять ресурсоёмкие операции с данными. Такие операции должны выполняться в фоновом режиме, вне потока пользовательского интерфейса (главного потока). Фоновые задачи потребляют ограниченные ресурсы устройства, такие как оперативная память и заряд аккумулятора. Неправильная обработка может привести к некомфортному опыту пользователя.
 В этой лабораторной работе вы узнаете, как использовать WorkManager для оптимального и эффективного планирования фоновых задач. Подробнее о других доступных решениях для фоновой обработки в Android см. в руководстве по фоновой обработке . 
Что вам уже следует знать
-  Как использовать компоненты архитектуры Android ViewModel,LiveDataиRoom.
-  Как выполнять преобразования в классе LiveData.
- Как построить и запустить сопрограмму .
- Как использовать адаптеры привязки при привязке данных.
- Как загрузить кэшированные данные с использованием шаблона репозитория.
Чему вы научитесь
-  Как создать Worker, представляющий единицу работы.
-  Как создать WorkRequestдля запроса на выполнение работы.
-  Как добавить ограничения в WorkRequest, чтобы определить, как и когда должен запускаться работник.
-  Как использовать WorkManagerдля планирования фоновых задач.
Что ты будешь делать?
- Создайте рабочий процесс для выполнения фоновой задачи по предварительной загрузке видеоплейлиста DevBytes из сети.
- Запланируйте периодический запуск рабочего процесса.
-  Добавьте ограничения в WorkRequest.
-  Запланируйте периодический WorkRequest, который будет выполняться раз в день.
В этой лабораторной работе вы будете работать над приложением DevBytes, которое разработали в предыдущей лабораторной работе. (Если у вас нет этого приложения, вы можете загрузить начальный код для этого урока.)
Приложение DevBytes отображает список видеороликов DevByte — коротких обучающих программ, созданных командой Google по работе с разработчиками Android . В видеороликах представлены функции для разработчиков и передовой опыт разработки для Android.
Вы улучшаете пользовательский опыт в приложении, предварительно загружая видео раз в день. Это гарантирует, что пользователь получит свежий контент сразу после открытия приложения.

В этом задании вы загрузите и проверите стартовый код.
Шаг 1: Загрузите и запустите стартовое приложение.
Вы можете продолжить работу с приложением DevBytes, которое вы создали в предыдущей лабораторной работе (если оно у вас есть). Также вы можете скачать стартовое приложение.
В этом задании вы загрузите и запустите стартовое приложение и изучите его код.
- Если у вас еще нет приложения DevBytes, загрузите стартовый код DevBytes для этой лабораторной работы из проекта DevBytesRepository на GitHub.
- Разархивируйте код и откройте проект в Android Studio.
- Подключите тестовое устройство или эмулятор к интернету, если оно ещё не подключено. Соберите и запустите приложение. Приложение загрузит список видео DevByte из сети и отобразит их.
- В приложении нажмите на любое видео, чтобы открыть его в приложении YouTube.
Шаг 2: Изучите код
 Стартовое приложение содержит большой объём кода, представленного в предыдущей лабораторной работе. Стартовый код для этой лабораторной работы включает модули сети, пользовательского интерфейса, автономного кэширования и репозитория. Вы можете сосредоточиться на планировании фоновой задачи с помощью WorkManager .
- В Android Studio разверните все пакеты.
-  Ознакомьтесь с пакетом database. Пакет содержит сущности базы данных и локальную базу данных, реализованную с помощьюRoom.
-  Изучите пакет repository. Он содержит классVideosRepository, который абстрагирует уровень данных от остальной части приложения.
- Изучите остальную часть начального кода самостоятельно и с помощью предыдущей лабораторной работы.
 WorkManager — один из компонентов архитектуры Android и часть Android Jetpack . WorkManager предназначен для фоновой работы, которая может быть отложена и требует гарантированного выполнения:
- Отложенность означает, что работа не требует немедленного выполнения. Например, отправка аналитических данных на сервер или синхронизация базы данных в фоновом режиме — это работа, которую можно отложить.
- Гарантированное выполнение означает, что задача будет выполнена даже в случае закрытия приложения или перезагрузки устройства.

 Выполняя фоновую задачу, WorkManager решает проблемы совместимости и применяет передовые методы для поддержания работоспособности аккумулятора и системы. WorkManager обеспечивает совместимость вплоть до уровня API 14. WorkManager выбирает подходящий способ планирования фоновой задачи в зависимости от уровня API устройства. Он может использовать JobScheduler (на API 23 и выше) или комбинацию AlarmManager и BroadcastReceiver . 
 WorkManager также позволяет задать критерии запуска фоновой задачи. Например, вы можете запускать задачу только при соблюдении определённых условий: состояния аккумулятора, сети или уровня заряда. Далее в этой практической работе вы узнаете, как устанавливать ограничения.
 В этой лабораторной работе вы запланируете задачу предварительной загрузки видеоплейлиста DevBytes из сети один раз в день. Для этого используется библиотека WorkManager . 
-  Откройте файл build.gradle (Module:app)и добавьте зависимостьWorkManagerк проекту.
 Если вы используете последнюю версию библиотеки, приложение-решение должно скомпилироваться должным образом. Если это не так, попробуйте решить проблему самостоятельно или вернитесь к версии библиотеки, указанной ниже.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"- Синхронизируйте свой проект и убедитесь в отсутствии ошибок компиляции.
 Прежде чем добавлять код в проект, ознакомьтесь со следующими классами в библиотеке WorkManager :
-  Worker
 В этом классе определяется фактическая работа (задача), которая будет выполняться в фоновом режиме. Вы расширяете этот класс и переопределяете методdoWork(). В методеdoWork()размещается код, который будет выполняться в фоновом режиме, например, синхронизация данных с сервером или обработка изображений. В этой задаче вы реализуетеWorker.
-  WorkRequest
 Этот класс представляет запрос на запуск задачи-воркера в фоновом режиме. ИспользуйтеWorkRequestдля настройки времени и времени запуска задачи-воркера с помощьюConstraints, таких как наличие подключенного устройства или подключение к сети Wi-Fi.WorkRequestреализуется в последующей задаче.
-  WorkManager
 Этот класс планирует и выполняет вашWorkRequest.WorkManagerпланирует рабочие запросы таким образом, чтобы равномерно распределить нагрузку на системные ресурсы, соблюдая заданные вами ограничения.WorkManagerреализуется в последующей задаче.
Шаг 1: Создание работника
 В этой задаче вы добавляете Worker для предварительной загрузки видеоплейлиста DevBytes в фоновом режиме.
-  Внутри пакета devbyteviewerсоздайте новый пакет с именемwork.
-  Внутри workпакета создайте новый класс Kotlin с именемRefreshDataWorker.
-  Расширьте класс RefreshDataWorkerиз классаCoroutineWorker. ПередайтеcontextиWorkerParametersв качестве параметров конструктора.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}-  Чтобы устранить ошибку абстрактного класса, переопределите метод doWork()внутри классаRefreshDataWorker.
override suspend fun doWork(): Result {
  return Result.success()
}Приостанавливающая функция — это функция, выполнение которой можно приостановить и возобновить позже. Приостанавливающая функция может выполнять длительную операцию и ожидать её завершения, не блокируя основной поток.
Шаг 2: Реализация doWork()
 Метод doWork() внутри класса Worker вызывается в фоновом потоке. Метод выполняет работу синхронно и должен возвращать объект ListenableWorker.Result . Система Android даёт Worker максимум 10 минут на завершение выполнения и возврат объекта ListenableWorker.Result . По истечении этого времени система принудительно останавливает Worker .
 Чтобы создать объект ListenableWorker.Result , вызовите один из следующих статических методов, чтобы указать статус завершения фоновой работы:
-  Result.success()— работа завершена успешно.
-  Result.failure()— работа завершена с постоянным сбоем.
-  Result.retry()— работа столкнулась с временным сбоем и должна быть повторена.
 В этой задаче вы реализуете метод doWork() для извлечения видеоплейлиста DevBytes из сети. Вы можете повторно использовать существующие методы класса VideosRepository для извлечения данных из сети.
-  В классе RefreshDataWorkerвнутриdoWork()создайте и создайте экземпляры объектаVideosDatabaseи объектаVideosRepository.
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)
   return Result.success()
}-  В классе RefreshDataWorker, внутриdoWork(), над операторомreturn, вызовите методrefreshVideos()в блокеtry. Добавьте журнал для отслеживания времени запуска рабочего процесса.
try {
   repository.refreshVideos( )
   Timber.d("Work request for sync is run")
   } catch (e: HttpException) {
   return Result.retry()
} Чтобы устранить ошибку «Неразрешенная ссылка», импортируйте retrofit2.HttpException .
-  Ниже для справки представлен полный класс 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 определяет единицу работы, а WorkRequest — как и когда должна выполняться работа. Существует две конкретные реализации класса WorkRequest :
-  Класс OneTimeWorkRequestпредназначен для одноразовых задач. ( Одноразовая задача выполняется только один раз.)
-  Класс PeriodicWorkRequestпредназначен для периодической работы, которая повторяется через определенные промежутки времени.
Задачи могут быть разовыми или периодическими, поэтому выбирайте класс соответственно. Подробнее о планировании повторяющихся задач см. в документации по повторяющимся задачам .
 В этой задаче вы определяете и планируете WorkRequest для запуска исполнителя, созданного вами в предыдущей задаче. 
Шаг 1: Настройте повторяющуюся работу
 В приложении Android класс Application является базовым классом, содержащим все остальные компоненты, такие как действия и сервисы. При создании процесса для вашего приложения или пакета класс Application (или любой Application подкласс) создаётся раньше любого другого класса.
 В этом примере приложения класс DevByteApplication является подклассом класса Application . Класс DevByteApplication — хорошее место для планирования WorkManager .
-  В классе DevByteApplicationсоздайте методsetupRecurringWork()для настройки повторяющейся фоновой работы.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}-  В методе setupRecurringWork()создайте и инициализируйте периодический рабочий запрос, который будет выполняться раз в день, используя методPeriodicWorkRequestBuilder(). Передайте классRefreshDataWorker, созданный в предыдущей задаче. Передайте интервал повторения1с единицей времениTimeUnit.DAYS.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .build() Чтобы устранить ошибку, импортируйте java.util.concurrent.TimeUnit . 
Шаг 2: Запланируйте WorkRequest с помощью WorkManager
 После определения WorkRequest вы можете запланировать его выполнение с помощью WorkManager , используя метод enqueueUniquePeriodicWork() . Этот метод позволяет добавить PeriodicWorkRequest с уникальным именем в очередь, где одновременно может быть активен только один PeriodicWorkRequest с определённым именем.
Например, вам может потребоваться активировать только одну операцию синхронизации. Если одна операция синхронизации ожидает выполнения, вы можете разрешить её выполнение или заменить новой работой, используя ExistingPeriodicWorkPolicy .
 Дополнительную информацию о способах планирования WorkRequest см. в документации WorkManager .
-  В начале класса RefreshDataWorkerдобавьте объект-компаньон. Определите имя для уникальной идентификации этого объекта.
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}-  В классе DevByteApplication, в конце методаsetupRecurringWork(), запланируйте работу с помощью методаenqueueUniquePeriodicWork(). Передайте перечислениеKEEPдля ExistingPeriodicWorkPolicy. ПередайтеrepeatingRequestв качестве параметраPeriodicWorkRequest.
WorkManager.getInstance().enqueueUniquePeriodicWork(
       RefreshDataWorker.WORK_NAME,
       ExistingPeriodicWorkPolicy.KEEP,
       repeatingRequest)Если существует отложенная (незавершенная) работа с тем же именем, параметр ExistingPeriodicWorkPolicy. заставляет KEEP сохранить предыдущую периодическую работу и отменить новый запрос WorkManager работу.
-  В начале класса DevByteApplicationсоздайте объектCoroutineScopeи передайтеDispatchers.Defaultв качестве параметра конструктора.
private val applicationScope = CoroutineScope(Dispatchers.Default)-  В классе DevByteApplicationдобавьте новый методdelayedInit()для запуска сопрограммы.
private fun delayedInit() {
   applicationScope.launch {
   }
}-  Внутри метода delayedInit()вызовитеsetupRecurringWork().
-  Перенесите инициализацию Timber из метода onCreate()в методdelayedInit().
private fun delayedInit() {
   applicationScope.launch {
       Timber.plant(Timber.DebugTree())
       setupRecurringWork()
   }
}-  В классе DevByteApplicationв конце методаonCreate()добавьте вызов методаdelayedInit().
override fun onCreate() {
   super.onCreate()
   delayedInit()
}-  Откройте панель Logcat в нижней части окна Android Studio. Отфильтруйте по RefreshDataWorker.
-  Запустите приложение. WorkManagerмгновенно запланирует вашу повторяющуюся работу.
 На панели Logcat обратите внимание на записи журнала, которые показывают, что запрос на работу запланирован, а затем успешно выполнен.
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
Журнал WM-WorkerWrapper отображается из библиотеки WorkManager , поэтому вы не можете изменить это сообщение журнала. 
Шаг 3: (Необязательно) Запланируйте WorkRequest на минимальный интервал
На этом этапе вы уменьшаете временной интервал с 1 дня до 15 минут. Это делается для того, чтобы можно было увидеть журналы выполнения периодического запроса на выполнение работ.
-  В классе DevByteApplication, внутри методаsetupRecurringWork(), закомментируйте текущее определениеrepeatingRequest. Добавьте новый запрос на работу с периодическим интервалом повторения15минут.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()-  Откройте панель Logcat в Android Studio и отфильтруйте данные по RefreshDataWorker. Чтобы очистить предыдущие журналы, нажмите значок «Очистить Logcat». . .
-  Запустите приложение, и WorkManagerнемедленно запланирует вашу повторяющуюся работу. На панели Logcat обратите внимание на журналы — запрос на работу выполняется каждые 15 минут. Подождите 15 минут, чтобы увидеть ещё один набор журналов запросов на работу. Вы можете оставить приложение запущенным или закрыть его; менеджер задач должен продолжать работать.
 Обратите внимание, что интервал иногда составляет менее 15 минут, а иногда более 15 минут. (Точное время зависит от оптимизации ОС по расходу заряда батареи.)
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
 Поздравляем! Вы создали воркер и запланировали запрос на выполнение работы с помощью WorkManager . Но есть проблема: вы не указали никаких ограничений. WorkManager будет планировать выполнение задачи один раз в день, даже если устройство разряжено, находится в спящем режиме или не подключено к сети. Это повлияет на заряд батареи и производительность устройства, а также может привести к ухудшению пользовательского опыта.
В следующей задаче вы решите эту проблему, добавив ограничения.
 В предыдущей задаче вы использовали WorkManager для планирования запроса на работу. В этой задаче вы добавляете критерии времени выполнения работы.
 При определении WorkRequest можно указать ограничения на время выполнения Worker . Например, можно указать, что работа должна выполняться только тогда, когда устройство находится в режиме ожидания или только когда оно подключено к сети и Wi-Fi. Вы также можете указать политику отсрочки для повторных попыток выполнения работы. Поддерживаемые ограничения — это методы, заданные в Constraints.Builder . Подробнее см. в разделе «Определение запросов на работу» .
Шаг 1: Добавьте объект «Ограничения» и задайте одно ограничение.
 На этом этапе вы создаёте объект Constraints и устанавливаете для него одно ограничение — сетевое. (Лог-файлы легче отслеживать, если задано только одно ограничение. На следующем этапе вы добавите другие ограничения.)
-  В классе DevByteApplication, в начале методаsetupRecurringWork(), определитеvalтипаConstraints. Используйте методConstraints.Builder().
val constraints = Constraints.Builder()Чтобы устранить ошибку, импортируйте androidx.work.Constraints .
-  Используйте метод setRequiredNetworkType(), чтобы добавить ограничение типа сети к объектуconstraints. Используйте перечислениеUNMETERED, чтобы запрос на работу выполнялся только при подключении устройства к безлимитной сети.
.setRequiredNetworkType(NetworkType.UNMETERED)-  Используйте метод build()для генерации ограничений из построителя.
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .build()Теперь вам нужно установить только что созданный объект Constraints для запроса на работу.
-  В классе DevByteApplication, в методеsetupRecurringWork(), установите объектConstraintsдля периодического запроса на работуrepeatingRequest. Чтобы установить ограничения, добавьте методsetConstraints()над вызовом методаbuild().
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()Шаг 2: Запустите приложение и просмотрите журналы.
На этом этапе вы запускаете приложение и замечаете, что ограниченный запрос на работу запускается в фоновом режиме с определенными интервалами.
- Удалите приложение с устройства или эмулятора, чтобы отменить все ранее запланированные задачи.
-  Откройте панель Logcat в Android Studio. На панели Logcat очистите предыдущие журналы, нажав на значок «Очистить Logcat».  слева. Фильтр по слева. Фильтр поwork.
- Отключите Wi-Fi на устройстве или эмуляторе, чтобы увидеть, как работают ограничения. Текущий код устанавливает только одно ограничение, указывающее, что запрос должен выполняться только в безлимитной сети. Поскольку Wi-Fi отключен, устройство не подключено к сети, ни с тарификацией, ни без тарификацией. Следовательно, это ограничение не будет соблюдено.
-  Запустите приложение и обратите внимание на панель Logcat . WorkManagerнемедленно планирует фоновую задачу. Поскольку сетевое ограничение не выполнено, задача не запускается.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
- Включите Wi-Fi на устройстве или эмуляторе и наблюдайте за панелью Logcat . Теперь запланированная фоновая задача запускается примерно каждые 15 минут, пока соблюдаются ограничения сети.
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 [...]
Шаг 3: Добавьте больше ограничений
 На этом этапе вы добавляете следующие ограничения в PeriodicWorkRequest :
- Батарея не разряжена.
- Зарядка устройства.
- Устройство находится в режиме ожидания; доступно только в API уровня 23 (Android M) и выше.
 Реализуйте следующее в классе DevByteApplication .
-  В классе DevByteApplicationв методеsetupRecurringWork()укажите, что запрос на выполнение работы должен выполняться только при достаточном уровне заряда батареи. Добавьте ограничение перед вызовом методаbuild()и используйте методsetRequiresBatteryNotLow().
.setRequiresBatteryNotLow(true)-  Обновите запрос на выполнение так, чтобы он выполнялся только во время зарядки устройства. Добавьте ограничение перед вызовом метода build()и используйте методsetRequiresCharging().
.setRequiresCharging(true)-  Обновите запрос на выполнение так, чтобы он выполнялся только при бездействии устройства. Добавьте ограничение перед вызовом метода build()и используйте методsetRequiresDeviceIdle(). Это ограничение запускает запрос на выполнение только тогда, когда пользователь не использует устройство активно. Эта функция доступна только в Android 6.0 (Marshmallow) и более поздних версиях, поэтому добавьте условие для версии SDKMи выше.
.apply {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
       setRequiresDeviceIdle(true)
   }
}Вот полное определение объекта 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()-  Внутри метода setupRecurringWork()измените интервал запроса обратно на один раз в день.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .setConstraints(constraints)
       .build()Ниже представлена полная реализация метода setupRecurringWork() с журналом, позволяющим отслеживать, когда запланирован периодический запрос на работу. 
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)
   }- Чтобы удалить ранее запланированный запрос на работу, удалите приложение DevBytes со своего устройства или эмулятора.
-  Запустите приложение, и WorkManagerнемедленно запланирует запрос на работу. Запрос на работу будет выполняться один раз в день при соблюдении всех ограничений.
- Этот рабочий запрос будет выполняться в фоновом режиме, пока установлено приложение, даже если оно не запущено. Поэтому вам следует удалить приложение с телефона.
 Отличная работа! Вы реализовали и запланировали экономичный для батареи запрос на ежедневную предварительную загрузку видео в приложении DevBytes. WorkManager запланирует и выполнит эту задачу, оптимизируя системные ресурсы. Ваши пользователи и их аккумуляторы будут очень довольны.
Проект Android Studio: DevBytesWorkManager .
-  API WorkManagerупрощает планирование откладываемых асинхронных задач, которые должны выполняться надежно.
-  Большинству реальных приложений необходимо выполнять длительные фоновые задачи. Для оптимального и эффективного планирования фоновой задачи используйте WorkManager.
-  Основными классами в библиотеке WorkManagerявляютсяWorker,WorkRequestиWorkManager.
-  Класс Workerпредставляет единицу работы. Чтобы реализовать фоновую задачу, расширьте классWorkerи переопределите методdoWork().
-  Класс WorkRequestпредставляет собой запрос на выполнение единицы работы.WorkRequest— базовый класс для указания параметров работы, которую вы планируете вWorkManager.
-  Существуют две конкретные реализации класса WorkRequest:OneTimeWorkRequestдля разовых задач иPeriodicWorkRequestдля периодических запросов на работу.
-  При определении WorkRequestможно указатьConstraintsуказывающие, когда следует запускатьWorker. Ограничения включают в себя, например, подключено ли устройство к сети, находится ли оно в режиме ожидания или подключено ли к сети Wi-Fi.
-  Чтобы добавить ограничения к WorkRequest, используйте методы set, перечисленные в документацииConstraints.Builder. Например, чтобы указать, чтоWorkRequestне должен запускаться при низком заряде батареи устройства, используйте метод set setsetRequiresBatteryNotLow().
-  После определения WorkRequestпередайте задачу системе Android. Для этого запланируйте её выполнение с помощью одного из методовenqueueWorkManager.
-  Точное время выполнения Workerзависит от ограничений, используемых вWorkRequest, и от системных оптимизаций.WorkManagerразработан для обеспечения наилучшего поведения с учётом этих ограничений.
Курс Udacity:
Документация для разработчиков Android:
- Определение ваших рабочих запросов
-  WorkManager
- Начало работы с WorkManager
- Повторяющаяся работа
- Руководство по фоновой обработке
Другой:
В этом разделе перечислены возможные домашние задания для студентов, работающих над этой лабораторной работой в рамках курса, проводимого преподавателем. Преподаватель должен выполнить следующие действия:
- При необходимости задавайте домашнее задание.
- Объясните учащимся, как следует сдавать домашние задания.
- Оцените домашние задания.
Преподаватели могут использовать эти предложения так часто или редко, как пожелают, и могут свободно задавать любые другие домашние задания, которые они сочтут подходящими.
Если вы работаете с этой лабораторной работой самостоятельно, можете использовать эти домашние задания для проверки своих знаний.
Вопрос 1
 Каковы конкретные реализации класса WorkRequest ?
 ▢ OneTimeWorkPeriodicRequest
 ▢ OneTimeWorkRequest и PeriodicWorkRequest
 ▢ OneTimeWorkRequest и RecurringWorkRequest
 ▢ OneTimeOffWorkRequest и RecurringWorkRequest
Вопрос 2
 Какой из следующих классов WorkManager использует для планирования фоновой задачи в API 23 и выше?
 ▢ Только JobScheduler
 ▢ BroadcastReceiver и AlarmManager
 ▢ AlarmManager и JobScheduler
 ▢ Scheduler и BroadcastReceiver
Вопрос 3
 Какой API вы используете для добавления ограничений в WorkRequest ?
 ▢ setConstraints()
 ▢ addConstraints()
 ▢ setConstraint()
 ▢ addConstraintsToWorkRequest() 
 Перейти к следующему уроку: 
Ссылки на другие практические занятия по этому курсу см. на целевой странице практических занятий по основам Android Kotlin .