当前位置: 首页 > article >正文

[ Android ] JetPack WorkManager Overview

文章目录

          • Add Dependency
          • Define Background Work
          • Submit Work Request
          • Handle One-Time Work
          • Handle Periodic Work
          • Handle In-Time Work
          • Work Constrains
          • Work Delayed
          • Retry Strategy
          • Cancel Work
          • Update Work
          • Deliver Parameters
          • Unique Work
          • Work Query
          • Work Chain
          • Work On Multi-Process
          • Disable Auto Startup for WorkManager

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)

http://www.kler.cn/a/488881.html

相关文章:

  • php函数性能优化中应注意哪些问题
  • 现代企业架构白皮书(可以在线阅读完整PDF文件)
  • 透明部署、旁路逻辑串联的区别
  • 机器学习无处不在,AI顺势而为,创新未来
  • C# XPTable 带图片的增删改查(XPTable控件使用说明十三)
  • 备考蓝桥杯:顺序表相关算法题
  • Qt初识——下载与环境配置
  • QTcpSocket 中设置接收缓冲区大小
  • 嵌入式C语言:二维数组
  • ZDH-调度服务
  • 人工智能-数据分析及特征提取思路
  • 【Vim Masterclass 笔记09】S06L22:Vim 核心操作训练之 —— 文本的搜索、查找与替换操作(第一部分)
  • scrapy爬取图片
  • 项目管理之引论
  • 预测市场平台 Aegis:Al Agent + Web3,为预测市场提供新的动力
  • 【JAVA面试】基本类型与包装类型
  • 利用Python爬虫技术从义乌购获取商品列表
  • AIP-1 AIP目的和指南
  • npm i 报错
  • 获得PostgreSQL中级认证后,可以从事哪些工作岗位?
  • USB学习——基本概念
  • Objective-C语言的软件工程
  • 从excel提取和过滤数据到echarts中绘制图
  • vulnhub靶场【DC系列】之5
  • 开源cJson用法
  • 汽车免拆诊断 | 2007款保时捷Carrera S车行驶中发动机冷却液温度报警灯异常点亮