Bỏ qua để đến nội dung

WorkManager

WorkManager xử lý background tasks cần đảm bảo thực thi, ngay cả khi app bị tắt.

Use Case Solution
Sync data định kỳ WorkManager
Upload logs WorkManager
Download files WorkManager
Immediate user task Coroutines
Foreground task Foreground Service
dependencies {
implementation("androidx.work:work-runtime-ktx:2.9.0")
}
class UploadWorker(
context: Context,
workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result {
return try {
val imageUri = inputData.getString("image_uri") ?: return Result.failure()
// Upload logic
uploadImage(imageUri)
// Return success with output
val outputData = workDataOf("upload_url" to "https://...")
Result.success(outputData)
} catch (e: Exception) {
if (runAttemptCount < 3) {
Result.retry()
} else {
Result.failure()
}
}
}
}
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setInputData(workDataOf("image_uri" to uri.toString()))
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
)
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
30, TimeUnit.SECONDS
)
.addTag("upload")
.build()
WorkManager.getInstance(context).enqueue(uploadRequest)
val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(
15, TimeUnit.MINUTES // Minimum 15 minutes
)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(
"sync_work",
ExistingPeriodicWorkPolicy.KEEP,
syncRequest
)
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) // Cần network
.setRequiredNetworkType(NetworkType.UNMETERED) // Cần WiFi
.setRequiresBatteryNotLow(true) // Battery > 20%
.setRequiresCharging(true) // Đang sạc
.setRequiresDeviceIdle(true) // Device idle
.setRequiresStorageNotLow(true) // Storage ok
.build()
WorkManager.getInstance(context)
.beginWith(downloadRequest)
.then(processRequest)
.then(uploadRequest)
.enqueue()
// Parallel then sequential
WorkManager.getInstance(context)
.beginWith(listOf(download1, download2, download3))
.then(mergeRequest)
.then(uploadRequest)
.enqueue()
WorkManager.getInstance(context)
.getWorkInfoByIdLiveData(uploadRequest.id)
.observe(lifecycleOwner) { workInfo ->
when (workInfo?.state) {
WorkInfo.State.ENQUEUED -> showPending()
WorkInfo.State.RUNNING -> showProgress()
WorkInfo.State.SUCCEEDED -> {
val url = workInfo.outputData.getString("upload_url")
showSuccess(url)
}
WorkInfo.State.FAILED -> showError()
WorkInfo.State.CANCELLED -> showCancelled()
else -> {}
}
}
// With Flow
WorkManager.getInstance(context)
.getWorkInfoByIdFlow(uploadRequest.id)
.collect { workInfo ->
// Handle state
}
// By ID
WorkManager.getInstance(context).cancelWorkById(uploadRequest.id)
// By tag
WorkManager.getInstance(context).cancelAllWorkByTag("upload")
// By unique name
WorkManager.getInstance(context).cancelUniqueWork("sync_work")
// All
WorkManager.getInstance(context).cancelAllWork()
class DownloadWorker(...) : CoroutineWorker(...) {
override suspend fun doWork(): Result {
val files = inputData.getStringArray("files") ?: return Result.failure()
files.forEachIndexed { index, file ->
downloadFile(file)
// Update progress
setProgress(workDataOf("progress" to (index + 1) * 100 / files.size))
}
return Result.success()
}
}
// Observe progress
workManager.getWorkInfoByIdFlow(request.id).collect { info ->
val progress = info?.progress?.getInt("progress", 0) ?: 0
updateProgressBar(progress)
}
val urgentRequest = OneTimeWorkRequestBuilder<UrgentWorker>()
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
@HiltWorker
class SyncWorker @AssistedInject constructor(
@Assisted context: Context,
@Assisted workerParams: WorkerParameters,
private val repository: DataRepository
) : CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result {
repository.sync()
return Result.success()
}
}

Feature Description
OneTimeWorkRequest Chạy một lần
PeriodicWorkRequest Chạy định kỳ (min 15 phút)
Constraints Điều kiện để chạy
Chaining Nối nhiều work
Result.retry() Thử lại nếu fail
setExpedited() Ưu tiên cao