[ Android ] JetPack WorkManager Overview

发布于:2025-02-10 ⋅ 阅读:(101) ⋅ 点赞:(0)

Add Dependency
dependencies {
    api("io.github.hellogoogle2000:android-commons:1.0.37")
    api("androidx.work:work-runtime:2.9.1")
    api("androidx.work:work-runtime-ktx:2.9.1")
    api("androidx.work:work-multiprocess:2.9.1")
}
Define Background Work
package workmanager

import android.content.Context
import androidx.work.Data
import androidx.work.Worker
import androidx.work.WorkerParameters
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking

class UploadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {

    override fun doWork(): Result {
        runBlocking {
            for (i in 0 until 10) {
                delay(3000)
                println("Upload Offline Task")
            }
        }
        val data = Data.Builder()
            .putInt("taskCount", 10)
            .build()
        return Result.success(data)
    }
}
Submit Work Request
package x.android.samples

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import workmanager.UploadWorker
import x.android.commons.context.Global
import x.android.samples.databinding.ActivityHomeBinding

class HomeActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityHomeBinding.inflate(layoutInflater)
        setContentView(binding.root)
        submitUploadWork()
    }

    private fun submitUploadWork() {
        val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>().build()
        WorkManager.getInstance(Global.app).enqueue(uploadWorkRequest)
    }
}
Handle One-Time Work

execute one time only

val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>().build()
Handle Periodic Work

execute once each time in given period

val uploadWorkRequest = PeriodicWorkRequestBuilder<ExpeditedUploadWorker>(1, TimeUnit.HOURS).build()
Handle In-Time Work

execute immediately, when you mark work as expedited

if you want works run immediately, or keep a long running time

you should declare and start a foreground service, to ensure background running permissions

val uploadWorkRequest = OneTimeWorkRequestBuilder<ExpeditedUploadWorker>()
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST).build()
package workmanager

import android.app.Notification
import android.content.Context
import android.graphics.BitmapFactory
import androidx.core.app.NotificationCompat
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
import kotlinx.coroutines.delay
import x.android.commons.context.Global

class ExpeditedUploadWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        setForeground(getForegroundInfo())
        for (i in 0 until 10) {
            delay(3000)
            println("Upload Offline Task")
        }
        return Result.success()
    }

    override suspend fun getForegroundInfo(): ForegroundInfo {
        return ForegroundInfo(0, createNotification())
    }

    private fun createNotification(): Notification {
        val context = Global.app
        val title = "WorkManager"
        val message = "Uploading Work is Running"
        val channel = "ForegroundService"
        val notificationBuilder = NotificationCompat.Builder(context, channel)
            .setLargeIcon(BitmapFactory.decodeResource(context.resources, x.android.commons.R.drawable.ic))
            .setSmallIcon(x.android.commons.R.drawable.ic)
            .setContentTitle(title)
            .setContentText(message)
        return notificationBuilder.build()
    }
}
<service
   android:name="androidx.work.impl.foreground.SystemForegroundService"
   android:foregroundServiceType="location|microphone"
   tools:node="merge" />
Work Constrains

limit when works can run

private fun submitUploadWork() {
    val constrains = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.UNMETERED)
        .setRequiresBatteryNotLow(true)
        .setRequiresCharging(true)
        .setRequiresDeviceIdle(true)
        .setRequiresStorageNotLow(true)
        .build()
    val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
        .setConstraints(constrains)
        .build()
    WorkManager.getInstance(Global.app).enqueue(uploadWorkRequest)
}
Work Delayed
OneTimeWorkRequestBuilder<UploadWorker>().setInitialDelay(10, TimeUnit.MINUTES)
Retry Strategy

retry after a backoff interval, if result failed and retry is requested

override suspend fun doWork(): Result {
    // ...
    return Result.retry()
}
private fun submitUploadWork() {
    val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
        .setBackoffCriteria(BackoffPolicy.LINEAR, 10 * 1000L, TimeUnit.MILLISECONDS)
        .build()
    WorkManager.getInstance(Global.app).enqueue(uploadWorkRequest)
}
Cancel Work

work states can be managed by id and tags, one work have unique id and multiple tags

private fun submitUploadWork() {
    val id = UUID.randomUUID()
    val tag = "upload"
    val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
        .setId(id)
        .addTag(tag)
        .addTag("other")
        .build()
    WorkManager.getInstance(Global.app).enqueue(uploadWorkRequest)
    WorkManager.getInstance(Global.app).cancelWorkById(id)
    WorkManager.getInstance(Global.app).cancelAllWorkByTag(tag)
    WorkManager.getInstance(Global.app).getWorkInfoById(id)
    WorkManager.getInstance(Global.app).getWorkInfosByTag(tag)
    WorkManager.getInstance(Global.app).getWorkInfosForUniqueWork("UploadWork")
}
Update Work

new request must have same id with previous one

workManager.updateWork(updatedWorkRequest)
Deliver Parameters

all data is delivered through a map-like struct

private fun submitUploadWork() {
    val input = workDataOf(
        "url" to "file://1.png",
        "name" to "1.png"
    )
    val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
        .setInputData(input)
        .build()
    WorkManager.getInstance(Global.app).enqueue(uploadWorkRequest)
}

override suspend fun doWork(): Result {
    val url = inputData.getString("url")
    return Result.success()
}
Unique Work

if same work exist, keep replace or append to it

WorkManager.getInstance(Global.app).enqueueUniqueWork("UploadWork", ExistingWorkPolicy.APPEND, uploadWorkRequest)

conflit strategy of unique work

  • KEEP
  • REPLACE
  • APPEND
  • APPEND_OR_REPLACE
Work Query
val workQuery = WorkQuery.Builder
    .fromTags(listOf("tag"))
    .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
    .addUniqueWorkNames(listOf("upload", "sync"))
    .build()
val workInfos = WorkManager.getInstance(Global.app).getWorkInfos(workQuery)
Work Chain

works can run in parallel on in serial

works submit in list will run in parallel

works concat with then will run in serial

if previous work failed, next works depend on it will also fail

private fun submitUploadWork() {
    val request1 = OneTimeWorkRequestBuilder<UploadWorker>().build()
    val request2 = OneTimeWorkRequestBuilder<UploadWorker>().build()
    val request3 = OneTimeWorkRequestBuilder<UploadWorker>().setInputMerger(ArrayCreatingInputMerger::class.java).build()
    val request4 = OneTimeWorkRequestBuilder<UploadWorker>().setInputMerger(ArrayCreatingInputMerger::class.java).build()
    val request5 = OneTimeWorkRequestBuilder<UploadWorker>().setInputMerger(ArrayCreatingInputMerger::class.java).build()
    val manager = WorkManager.getInstance(Global.app)
    manager.beginWith(listOf(request1, request2))
        .then(listOf(request3, request4))
        .then(request5)
        .enqueue()
}
Work On Multi-Process
package workmanager

import android.content.Context
import androidx.work.WorkerParameters
import androidx.work.multiprocess.RemoteCoroutineWorker
import kotlinx.coroutines.delay

class UploadWorker(context: Context, params: WorkerParameters) : RemoteCoroutineWorker(context, params) {

    override suspend fun doRemoteWork(): Result {
        for (i in 0 until 10) {
            delay(3000)
            println("Upload Offline Task")
        }
        return Result.success()
    }
}
private fun submitUploadWork() {
    val packageName = Global.app.packageName
    val componentName = ComponentName(packageName, RemoteWorkerService::class.java.name)
    val input = Data.Builder()
        .putString(ARGUMENT_PACKAGE_NAME, packageName)
        .putString(ARGUMENT_CLASS_NAME, componentName.className)
        .build()
    val request = OneTimeWorkRequestBuilder<UploadWorker>()
        .setInputData(input)
        .build()
    val manager = WorkManager.getInstance(Global.app)
    manager.enqueue(request)
}
<service
    android:name="androidx.work.multiprocess.RemoteWorkerService"
    android:exported="false"
    android:process=":RemoteWorkManager" />
Disable Auto Startup for WorkManager

the androidx.startup.InitializationProvider manage all startup work for jetpack components

the androidx.work.WorkManagerInitializer manage startup work for work manager component

if you want disable all auto startup components, remove InitializationProvider from manifest

if you just want to disable auto startup of work manager, remove WorkManagerInitializer from manifest

then you should start work manager by calling WorkManager.initialize manually

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="x.android.samples.androidx-startup"
    tools:node="remove">
</provider>
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="x.android.samples.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <meta-data
        android:name="androidx.work.WorkManagerInitializer"
        android:value="androidx.startup"
        tools:node="remove" />
</provider>
val configuration = Configuration.Builder()
    .setMinimumLoggingLevel(Log.ERROR)
    .build()
WorkManager.initialize(Global.app, configuration)

网站公告

今日签到

点亮在社区的每一天
去签到