持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
Android 玩转WorkManager(一)
WorkManager 是Android JetPack库中的成员之一,主要用作处理后台任务,它可以允许你创建一个立即运行或者是在给定条件下触发的任务,WorkerManger有一个持久化特性就是WorkManger在底层使用了Room来保证进程被结束或者是设备重启后,任务任然可以重新执行。并且WorkManager可以设置一个任务链,在上一个任务执行完成之后会自动执行下一个在链中排队的任务
WorkManager导航架构图
WorkerManger中主要有以下组成:
WorkManger:接收带参数和约束条件的WorkRequest,并将其排入队列
Worker:任务队列的最小执行单位,需要实现doWork()方法,它是执行在一个单独的后台进程中,所有需要在后台执行的任务都 在这个方法内完成
WorkRequest:给Worker设置参数和约束条件等,比如联网触发任务等worker执行触发条件都是可以通过它来设置
WorkResult: Worker的执行结果只要包含 Success, Failure, Retry
WorkStatus: workerManager为Request提供了一个LiveData,通过LiveData来获取当前任务的执行状态
WorkManger
WorkManger工作流程
//可以从源码看出在Api >= 23的时候底层是使用JobScheduler来实现的任务调度服务
public static final int MIN_JOB_SCHEDULER_API_LEVEL = 23;
@NonNull
static Scheduler createBestAvailableBackgroundScheduler(
@NonNull Context context,
@NonNull WorkManagerImpl workManager) {
Scheduler scheduler;
if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
scheduler = new SystemJobScheduler(context, workManager);
setComponentEnabled(context, SystemJobService.class, true);
Logger.get().debug(TAG, "Created SystemJobScheduler and enabled SystemJobService");
} else {
//设备是否能访问Google Play Services 不能就使用AlarmManager来实现
scheduler = tryCreateGcmBasedScheduler(context);
if (scheduler == null) {
scheduler = new SystemAlarmScheduler(context);
setComponentEnabled(context, SystemAlarmService.class, true);
Logger.get().debug(TAG, "Created SystemAlarmScheduler");
}
}
return scheduler;
}
WorkManger主要作用:对WorkRequest进行管理,包括执行,控制,取消,观察执行消息
//通过enqueue()将quest加入到任务队列
WorkManager.getInstance().enqueue(workerRequest)
//观察指定的worker的执行状态 getWorkInfoByIdLiveData()该方法会返回一个Livedata
workManager.getInstance().getWorkInfoByIdLiveData(workerRequest.id)
//可以通过一些Api构建任务链
/**
*
* workerRequest1
* |
* +---------
* workerRequest2
* |
* +--------------+
* | |
* workerRequest3 workerRequest4
*/
workManager.getInstance()
.beginWith(workerRequest1) //添加起始任务
.then(workerRequest2) //workerRequest1执行完毕之后执行单个任务workerRequest2
.then(listof(workerRequest3,workerRequest4)) // workerRequest2 执行任务列表
.enqueue()
Worker
Worker主要分为两类:一次性Worker(OneTimeWorkRequest) 和周期性Worker(PeriodicWorkRequest)
Worker生命周期图:
一次性工作的状态
public enum State {
//用于指示当WorkRequest的Constraints被满足并且资源可用时,WorkRequest被排队并且有资格运行。
ENQUEUED,
// 用于指示工作请求当前正在执行
RUNNING,
/**
*用于指示WorkRequest已在成功状态下完成。注意,PeriodicWorkRequests永远不会进入这种状态(它们将简单地返回到 * ENQUEUED并且有资格再次运行)。
*/
SUCCEEDED,
//用于指示WorkRequest已在失败状态下完成。所有相关的工作也将被标记为#FAILED,并且永远不会运行。
FAILED,
//用于指示WorkRequest当前被阻塞,因为它的先决条件还没有成功完成。
BLOCKED,
//用于指示WorkRequest已被取消且不会执行。所有相关的工作也将被标记为#CANCELLED,并且不会运行。
CANCELLED;
public boolean isFinished() {
return (this == SUCCEEDED || this == FAILED || this == CANCELLED);
}
SUCCEEDED、FAILED 和 CANCELLED 均表示此工作的终止状态。
如果您的工作处于上述任何状态WorkInfo.State.isFinished() 都将返回 true。下图如果worker设置了重试回退策略,在Worker运行的时候如果返回retry() 此时就会进行回退策略
周期性工作的状态
怎么创建Worker?
class PrintWorker constructor(
val context: Context,
val workerParameters: WorkerParameters
) : Worker(context, workerParameters) {
override fun doWork(): Result {
//需要执行的工作
}
}
/**
*1、除了可以使用Java实现的Worker之外还可以使用kotlin实现的CoroutineWorker
*2、CoroutineWorker会自动帮你处理任务的暂停和取消 该协程默认实在Dispatchers.Default上启动 可以使用*withContext()进行配置
*3、与Worker不同CoroutineWorker中的代码不会再WorkManager的Configuration 中指定的 Executor 上运行。
*/
class PrintWorker constructor(
val context: Context,
val workerParameters: WorkerParameters
) : CoroutineWorker(context, workerParameters) {
override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
//需要执行的工作
}
}
WorkRequest
WorkRequest中包含了WorkManager对WorkRequest对其进行调度和运行工作所需的所有信息,比如工作的约束条件,回退策略,回退基数,延时启动等配置信息
//传入数据
val data = Data.Builder().pusString("key","value").build()
/**********************约束条件************************/
val constrains = Constraints.Builder()
constrains.setRequiresDeviceIdle(true)//如果我们想让它在进入 Doze 模式时工作,我们只需要将其设置为 true
constrains.setRequiresNetworkType(NetWorkType.CONNECTED) // 我们可以设置互联网连接状态。
constrains.setRequiresBatteryNotLow(true) //如果电池电量不低,我们可以设置它的状态。默认值为假。
constrains.setRequiresCharging(true) //插入状态。默认值为假。
val workRequest = OneTimeWorkRequest.Builder(OneTimeWorker::class.java)
.setConstraints(constrains) //设置约束
.setInputData(data) //设置传入数据
.setInitialDelay(20,TimeUnit.SECONDS)
//worker中的doWork()方法通过inputData获取传入数据
do work(){
}