Jetpack WorkManager 看这一篇就够了| 开发者说·DTalk
The following article is from Android技术圈 Author 黄林晴
什么是 WorkManager
任务类型
WorkManager 任务类型分为立即运行、长期运行和延期执行,使用方式与周期关系如下所示:
一次性 | OneTimeWorkRequest 和 Worker。如需处理加急工作,请对 OneTimeWorkRequest 调用 setExpedited()。 | |
长期运行 | 一次性或定期 | 任意 WorkRequest 或 Worker。在工作器中调用 setForeground() 来处理通知。 |
可延期 | 一次性或定期 | PeriodicWorkRequest 和 Worker。 |
入门使用
添加依赖库
def work_version = "2.7.1"
implementation "androidx.work:work-runtime-ktx:$work_version"
定义工作 Worker
class UploadLogWorker(context: Context, workerParams: WorkerParameters) :
Worker(context, workerParams) {
override fun doWork(): Result {
Log.d("打印线程", Thread.currentThread().name)
return Result.success()
}
}
创建任务请求 WorkRequest
val uploadLogWorkerRequset: WorkRequest = OneTimeWorkRequestBuilder<UploadLogWorker>().build()
将任务提交系统
WorkManager.getInstance(this).enqueue(uploadLogWorkerRequset)
为任务传递参数
val uploadLogWorkerRequset: WorkRequest = OneTimeWorkRequestBuilder<UploadLogWorker>()
.setInputData(workDataOf("filePath" to "file://***", "fileName" to "log.txt"))
.build()
override suspend fun doWork(): Result {
val filePath = inputData.getString("filePath")
val fileName = inputData.getString("fileName")
Log.d("接受的参数", "$fileName:$filePath")
return Result.retry()
}
执行加急工作所需要知道的
val uploadLogWorkerRequset: WorkRequest = OneTimeWorkRequestBuilder<UploadLogWorker>()
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
枚举值 | 含义 |
RUN_AS_NON_EXPEDITED_WORK_REQUEST | 当系统无法为任务加急处理时,任务变成常规任务 |
DROP_WORK_REQUEST | 当系统无法为任务加急处理时,删除该任务 |
从官方我们获取到了这些信息: 在 Android 12 之前,工作器中的 getForegroundInfoAsync() 和 getForegroundInfo() 方法可让 WorkManager 在您调用 setExpedited() 时显示通知。如果您想要请求任务作为加急作业运行,则所有的 ListenableWorker 都必须实现 getForegroundInfo 方法。
如果未能实现对应的 getForegroundInfo 方法,那么在旧版平台上调用 setExpedited 时,可能会导致运行时崩溃。
了解到了这些,那我们就来实现 getForegroundInfo() 方法,修改 UploadLogWorker 代码如下所示:
class UploadLogWorker(context: Context, workerParams: WorkerParameters) :
Worker(context, workerParams) {
override fun doWork(): Result {
Log.d("打印线程", Thread.currentThread().name)
setForegroundAsync(getForegroundInfo())
return Result.success()
}
@SuppressLint("RestrictedApi")
override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> {
val future = SettableFuture.create<ForegroundInfo>()
future.set(getForegroundInfo())
return future
}
fun getForegroundInfo(): ForegroundInfo {
val notificationManager =
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"1",
"hh",
NotificationManager.IMPORTANCE_HIGH
)
notificationManager.createNotificationChannel(channel)
}
val notification = NotificationCompat.Builder(applicationContext, "1")
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle(applicationContext.getString(R.string.app_name))
.setContentText("我是一个上传日志的任务")
.build()
return ForegroundInfo(1337, notification)
}
}
协程工作 CoroutineWorker
将继承类修改为 CoroutineWorker;
实现 getForegroundInfo 方法,内容与上 getForegroundInfo 一致。
定时任务 PeriodicWorkRequest
val uploadLogWorkerRequset: WorkRequest = PeriodicWorkRequestBuilder<UploadLogWorker>(15,TimeUnit.MINUTES)
.build()
工作约束、延迟执行和重试策略
工作约束
很多情况下,我们需要为任务添加工作约束,比如上传日志的任务肯定是在有网络的条件下进行的,当前支持的约束条件如下所示。
NetworkType | 约束运行工作所需的网络类型。例如 Wi-Fi (UNMETERED)。 |
BatteryNotLow | 如果设置为 true,那么当设备处于 "电量不足模式" 时,工作不会运行。 |
RequiresCharging | 如果设置为 true,那么工作只能在设备充电时运行。 |
DeviceIdle | 如果设置为 true,则要求用户的设备必须处于空闲状态,才能运行工作。在运行批量操作时,此约束会非常有用;若是不用此约束,批量操作可能会降低用户设备上正在积极运行的其他应用的性能。 |
StorageNotLow | 如果设置为 true,那么当用户设备上的存储空间不足时,工作不会运行。 |
val constraints = Constraints.Builder()
.setRequiresCharging(true)
.build()
val uploadLogWorkerRequset: WorkRequest = OneTimeWorkRequestBuilder<UploadLogWorker>()
.setConstraints(constraints)
.build()
延迟执行
val uploadLogWorkerRequset: WorkRequest = OneTimeWorkRequestBuilder<UploadLogWorker>()
.setConstraints(constraints)
.setInitialDelay(5,TimeUnit.SECONDS)
.build()
重试策略
在 3.2 中定义 Work 中我们提到了 Result.retry 可以让任务重试,我们也可以自定义任务的重试策略和退避政策,我们通过具体的例子来解释。
val uploadLogWorkerRequset: WorkRequest = OneTimeWorkRequestBuilder<UploadLogWorker>()
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL, OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
TimeUnit.MILLISECONDS
)
.build()
观察工作执行结果
WorkManager.getInstance(this).getWorkInfoByIdLiveData(uploadLogWorkerRequset.id).observe(this){
if (it.state == WorkInfo.State.SUCCEEDED){
Toast.makeText(this,"任务执行成功,更新UI",Toast.LENGTH_LONG).show()
}else{
//任务失败或重试
}
}
总结
特性及注意事项
长按右侧二维码
查看更多开发者精彩分享
"开发者说·DTalk" 面向