WorkManager для Kotlin: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в 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) {                    

Рекомендаций