Представьте, что вашему приложению нужно синхронизировать данные с сервером, отправить аналитику или сжать фотографии, но вы не хотите заставлять пользователя ждать. Можно попробовать запустить задачу в фоновом потоке, однако, если закрыть приложение, всё прервётся. Android Studio предоставляет отличное решение — WorkManager. Эта библиотека гарантирует, что ваша работа будет выполнена, даже если телефон перезагрузят. А благодаря Kotlin и корутинам код остаётся простым и понятным. Этот урок как раз о том, как настроить фоновую задачу с нуля.
Что такое WorkManager и когда его использовать
WorkManager — это часть Android Jetpack, предназначенная для отложенных и гарантированных фоновых задач. В отличие от корутин, которые живут только пока работает приложение, или AlarmManager, который сложен в настройке, WorkManager сам выбирает подходящий способ выполнения в зависимости от версии Android. Он поддерживает периодические задачи, цепочки зависимостей и наблюдение за прогрессом.
Типичные сценарии: синхронизация локальной базы данных с сервером раз в сутки, загрузка обновлений, очистка кэша старых файлов. Главное правило: если задача должна завершиться обязательно, даже если пользователь свернул приложение, выбирайте WorkManager.
Добавление библиотеки в проект
Для начала откройте build.gradle.kts уровня модуля и добавьте зависимость. На момент написания статьи актуальна версия 2.10.0, совместимая с Kotlin 2.1.x.
dependencies {
implementation("androidx.work:work-runtime-ktx:2.10.0")
}
После синхронизации Gradle можно сразу создавать первую фоновую задачу. Никаких дополнительных разрешений в манифесте не требуется.
Создание простого Worker
Основной элемент — класс, наследующий CoroutineWorker. В нём нужно реализовать метод doWork(), который возвращает результат: Result.success(), Result.failure() или Result.retry(). Корутины позволяют использовать suspend-функции прямо внутри.
import android.content.Context
import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
class SyncWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
// имитация долгой работы: синхронизация данных
Log.d("SyncWorker", "Синхронизация началась")
// здесь мог бы быть вызов Retrofit
Log.d("SyncWorker", "Синхронизация завершена")
Result.success()
} catch (e: Exception) {
Result.retry() // попробовать ещё раз при ошибке
}
}
}
Запуск задачи из Activity или ViewModel
Чтобы запланировать работу, создайте объект OneTimeWorkRequest и передайте его в WorkManager. Можно задать ограничения — например, выполнять только при наличии интернета.
import androidx.work.Constraints
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(constraints)
.build()
WorkManager.getInstance(context).enqueue(syncRequest)
Теперь работа гарантированно выполнится, даже если сразу после вызова свернуть приложение. WorkManager сам выберет момент, когда устройство не занято и соблюдены ограничения.
Наблюдение за состоянием работы
Иногда нужно показать пользователю прогресс или обновить интерфейс после завершения. Для этого используют LiveData или Flow, возвращаемые WorkManager.
WorkManager.getInstance(context)
.getWorkInfoByIdLiveData(syncRequest.id)
.observe(lifecycleOwner) { workInfo ->
if (workInfo != null && workInfo.state == WorkInfo.State.SUCCEEDED) {
// обновить UI
}
}
Если вы используете Compose, можно обернуть LiveData в observeAsState() или напрямую подписаться на Flow через collectAsState().
Периодические задачи
Для регулярной синхронизации, например раз в 12 часов, используйте PeriodicWorkRequestBuilder. Минимальный интервал — 15 минут, система сама сгруппирует задачи для экономии батареи.
val periodicRequest = PeriodicWorkRequestBuilder<SyncWorker>(
12, TimeUnit.HOURS
)
.setConstraints(constraints)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"daily_sync",
ExistingPeriodicWorkPolicy.KEEP, // не дублировать, если уже есть
periodicRequest
)
Метод enqueueUniquePeriodicWork предотвращает создание дубликатов: если задача с таким именем уже существует, она не будет добавлена повторно.
Практические советы
- Не злоупотребляйте частотой. Периодические задачи чаще 15 минут запрещены системой. Для более частых обновлений используйте корутины внутри приложения.
- Обрабатывайте retry. Если
doWork()возвращаетResult.retry(), WorkManager повторит задачу с экспоненциальной задержкой. - Передавайте параметры. В
Workerможно передать данные черезsetInputData()и получить их внутри черезinputData. - Тестируйте. WorkManager предоставляет тестовый контекст
TestListenableWorkerBuilderдля модульных тестов.
Итог
Сегодня в статье были показаны примеры использования Kotlin и WorkManager. Вы изучили создание Worker, настройку ограничений и запуск как однократных, так и периодических задач. Теперь ваше приложение может выполнять синхронизацию, очистку кэша или отправку логов, не опасаясь прерывания из-за закрытия экрана. Этот шаг важен для профессиональной разработки на Android с использованием современных инструментов.