Введение в WorkManager для Kotlin
WorkManager — это библиотека от Google для Android, предназначенная для выполнения фоновых задач, которые должны быть гарантированно выполнены даже при перезагрузке устройства или закрытии приложения. Она является частью Android Jetpack и предоставляет простой и надёжный API для планирования отложенных, периодических и одноразовых задач.
Основная цель WorkManager — заменить устаревшие механизмы фоновой работы, такие как Service или AsyncTask, и обеспечить совместимость с различными версиями Android (от API 14+). Библиотека автоматически выбирает оптимальный способ выполнения задачи: JobScheduler (API 23+), AlarmManager + BroadcastReceiver (более старые версии) или Firebase JobDispatcher (если подключён).
WorkManager идеально подходит для таких сценариев, как: синхронизация данных с сервером, отправка аналитики, загрузка файлов, обработка изображений, резервное копирование, отправка push-уведомлений и любые другие задачи, которые не требуют немедленного выполнения, но должны быть завершены в ближайшее время.
Установка WorkManager
WorkManager не устанавливается через pip или npm, так как это библиотека для Android (Kotlin/Java). Для её добавления в проект необходимо модифицировать файл build.gradle (уровень модуля).
Шаг 1: Откройте файл build.gradle вашего модуля (app/build.gradle).
Шаг 2: Добавьте зависимость в блок dependencies:
dependencies {
implementation "androidx.work:work-runtime-ktx:2.9.0"
}
Шаг 3: Синхронизируйте проект (Sync Now).
Если вы используете Kotlin DSL, зависимость будет выглядеть так:
dependencies {
implementation("androidx.work:work-runtime-ktx:2.9.0")
}
Важно: Версия 2.9.0 — актуальная на момент написания статьи. Рекомендуется проверять последнюю версию на официальном сайте Android Developers.
Быстрый старт с примером кода
Рассмотрим простейший пример: создадим фоновую задачу, которая выводит лог в Logcat.
Шаг 1: Создайте класс Worker
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters
class SimpleWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
Log.d("SimpleWorker", "Фоновая задача выполнена!")
// Здесь можно выполнить любую длительную операцию
return Result.success()
}
}
Шаг 2: Запланируйте выполнение задачи
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
val workRequest = OneTimeWorkRequestBuilder<SimpleWorker>()
.build()
WorkManager.getInstance(context).enqueue(workRequest)
После вызова enqueue() задача будет выполнена в ближайшее время (обычно в течение нескольких секунд, если нет ограничений).
Основные методы и функции WorkManager
1. OneTimeWorkRequestBuilder
Что делает: Создаёт одноразовый запрос на выполнение задачи. Задача выполняется один раз и затем удаляется из очереди.
Параметры:
workerClass(обязательный) — класс, наследующий отWorkerилиCoroutineWorker.setInitialDelay()— задержка перед выполнением (в миллисекундах).setConstraints()— ограничения (например, подключение к интернету).addTag()— тег для группировки задач.setInputData()— входные данные для Worker.
Пример:
val request = OneTimeWorkRequestBuilder<SimpleWorker>()
.setInitialDelay(5, TimeUnit.SECONDS)
.addTag("my_tag")
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
WorkManager.getInstance(context).enqueue(request)
2. PeriodicWorkRequestBuilder
Что делает: Создаёт периодический запрос для повторяющихся задач. Минимальный интервал — 15 минут.
Параметры:
workerClass— класс Worker.repeatInterval— интервал повторения.timeUnit— единица времени (TimeUnit).setFlexTimeInterval()— гибкий интервал (задача может выполниться в течение этого окна).
Пример:
val periodicRequest = PeriodicWorkRequestBuilder<SimpleWorker>(
15, TimeUnit.MINUTES
)
.setConstraints(
Constraints.Builder()
.setRequiresCharging(true)
.build()
)
.build()
WorkManager.getInstance(context).enqueue(periodicRequest)
3. WorkManager.enqueue()
Что делает: Добавляет задачу в очередь выполнения. WorkManager гарантирует, что задача будет выполнена, даже если приложение будет закрыто.
Параметры:
workRequest— объектWorkRequest(одноразовый или периодический).
Пример:
val request = OneTimeWorkRequestBuilder<SimpleWorker>().build()
WorkManager.getInstance(context).enqueue(request)
4. WorkManager.enqueueUniqueWork()
Что делает: Добавляет уникальную задачу с указанным именем. Если задача с таким именем уже существует, поведение определяется политикой ExistingWorkPolicy.
Параметры:
uniqueWorkName— уникальное имя задачи.existingWorkPolicy— политика:KEEP,REPLACE,APPENDилиAPPEND_OR_REPLACE.workRequest— запрос.
Пример:
WorkManager.getInstance(context).enqueueUniqueWork(
"sync_data",
ExistingWorkPolicy.REPLACE,
request
)
5. WorkManager.cancelWorkById()
Что делает: Отменяет задачу по её уникальному идентификатору (UUID).
Параметры:
id— UUID задачи.
Пример:
val workId = request.id
WorkManager.getInstance(context).cancelWorkById(workId)
6. WorkManager.cancelAllWorkByTag()
Что делает: Отменяет все задачи с указанным тегом.
Параметры:
tag— строка тега.
Пример:
WorkManager.getInstance(context).cancelAllWorkByTag("my_tag")
7. WorkManager.getWorkInfoByIdLiveData()
Что делает: Возвращает LiveData с информацией о состоянии задачи. Позволяет наблюдать за выполнением.
Параметры:
id— UUID задачи.
Пример:
val workManager = WorkManager.getInstance(context)
workManager.getWorkInfoByIdLiveData(workId).observe(this) { workInfo ->
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
Log.d("WorkManager", "Задача успешно выполнена")
}
}
8. WorkManager.getWorkInfosByTagLiveData()
Что делает: Возвращает LiveData со списком WorkInfo для всех задач с указанным тегом.
Параметры:
tag— строка тега.
Пример:
workManager.getWorkInfosByTagLiveData("my_tag").observe(this) { workInfos ->
for (info in workInfos) {
Log.d("WorkManager", "Состояние: ${info.state}")
}
}
9. Constraints.Builder
Что делает: Создаёт ограничения для выполнения задачи. WorkManager будет ждать, пока все ограничения не будут выполнены.
Параметры:
setRequiredNetworkType()— тип сети (CONNECTED, UNMETERED, NOT_ROAMING).setRequiresCharging()— требуется ли зарядка.setRequiresDeviceIdle()— требуется ли режим ожидания устройства.setRequiresStorageNotLow()— требуется ли достаточное место на диске.
Пример:
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build()
10. ListenableWorker и CoroutineWorker
Что делает: Базовые классы для создания Worker. CoroutineWorker — для Kotlin Coroutines, ListenableWorker — для ручного управления потоками.
Параметры:
context— контекст приложения.workerParams— параметры задачи.
Пример с CoroutineWorker:
class CoroutineWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
delay(1000) // имитация работы
return Result.success()
}
}
Реальный практический пример использования
Рассмотрим реальный сценарий: приложение для заметок, которое каждые 30 минут синхронизирует данные с сервером, но только при наличии Wi-Fi и зарядки.
1. Создаём Worker для синхронизации:
class SyncWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
// Получаем данные из локальной базы данных
val localNotes = NotesRepository.getAllNotes()
// Отправляем на сервер
val response = apiService.syncNotes(localNotes)
if (response.isSuccessful) {
Log.d("SyncWorker", "Синхронизация успешна")
Result.success()
} else {
Log.e("SyncWorker", "Ошибка сервера: ${response.code()}")
Result.retry()
}
} catch (e: Exception) {
Log.e("SyncWorker", "Исключение: ${e.message}")
Result.retry()
}
}
}
2. Планируем периодическую задачу:
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED) // только Wi-Fi
.setRequiresCharging(true)
.build()
val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(
30, TimeUnit.MINUTES
)
.setConstraints(constraints)
.addTag("sync")
.build()
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(
"sync_notes",
ExistingPeriodicWorkPolicy.KEEP,
syncRequest
)
3. Наблюдаем за состоянием:
WorkManager.getInstance(context)
.getWorkInfosByTagLiveData("sync")
.observe(this) {