WorkManager完全解析+重构轮询系统

栏目: Android · 发布时间: 5年前

内容简介:之前用IntentService写了一个轮询框架,但是并不是很好,后面一直想找个其他方式来改写一下,找了好多资料发现了WorkManager,WorkManager是google提供的一个非常优秀的后台任务管理框架,对于提交给WorkManager的任务可以立即执行也可以在适当的时候执行,可以执行一次也可以根据条件循环执行多次,并且对于多个任务WorkManager可以管理任务的执行路径先后执行顺序等。本文先介绍WorkManager的用法,然后使用WorkManager来重构之前的轮询框架。WorkMan

之前用IntentService写了一个轮询框架,但是并不是很好,后面一直想找个其他方式来改写一下,找了好多资料发现了WorkManager,WorkManager是google提供的一个非常优秀的后台任务管理框架,对于提交给WorkManager的任务可以立即执行也可以在适当的时候执行,可以执行一次也可以根据条件循环执行多次,并且对于多个任务WorkManager可以管理任务的执行路径先后执行顺序等。本文先介绍WorkManager的用法,然后使用WorkManager来重构之前的轮询框架。

什么是Workmanager

WorkManager是google提供的异步执行任务的管理框架,会根据手机的API版本和应用程序的状态来选择适当的方式执行任务。当应用在运行的时候会在应用的进程中开一条线程来执行任务,当退出应用时,WorkManager会选择根据设备的API版本使用适合的算法调用JobScheduler或者Firebase JobDispatcher,或者AlarmManager来执行任务。如下图:

WorkManager完全解析+重构轮询系统

由上图可以看出WorkManager管理任务执行时底层还是调用了JobScheduler,JobDispatcher,AlarmManager,不过WorkManager会根据Android系统的API和应用的运行状态来选择合适的方式执行,并不用我们自己去考虑应用复杂的运行状态来进行选择使用JobScheduler还是JobDispatcher或者AlarmManager调用规则如下图:

WorkManager完全解析+重构轮询系统

WorkManager在项目中配置

使用WorkManager需要gradle依赖,进行一下简单配置就可以使用了。找到项目中的 app/build.gradle 目录下在上面加上下面的依赖。

dependencies {
    // 其他依赖配置
    def work_version = "1.0.0-beta02"
    implementation "android.arch.work:work-runtime:$versions.work"
}
复制代码

可以在 developer.android.com/topic/libra… 获取当前的work-runtime版本并且设置正确的版本号。

WorkManager主要类及使用

如下图给出了WorkManager中主要的类以及关系图,黄色区域是最主要的三个类,构成了WorkManager的基本框架,红色部分和绿色部分是关联的黄色部分的具体实现或者类里面包含一些规则或数据。

WorkManager完全解析+重构轮询系统
1、Worker处理要执行的任务的具体逻辑。

2、WorkerRequest代表一个独立的可以执行的任务,以及任务执行时的条件和规则,比如说任务执行一次还是多次以及任务的触发条件是什么任务有什么约束等。

3、WorkManager提供队列将要执行的WorkerRequest放到队列中管理和执行。如下图,三个主要类的关系:

WorkManager完全解析+重构轮询系统

下面分别介绍三个类的作用和使用方法。

Worker

Worker是一个抽象类,当有一个要执行的任务的时候可以继承Worker类,重写doWork()方法在doWork()方法中实现具体任务的逻辑。

public class MyWorker extends Worker {
    public MyWorker(
            @NonNull Context appContext,
            @NonNull WorkerParameters workerParams) {
        super(appContext, workerParams);
    }
    @NonNull
    @Override
    public Worker.Result doWork() {

        Context applicationContext = getApplicationContext();

        try {

            Bitmap picture = BitmapFactory.decodeResource(
                    applicationContext.getResources(),
                    R.drawable.test);
                    
            return Worker.Result.SUCCESS;
            
        } catch (Throwable throwable) {
        
            return Worker.Result.FAILURE;
            
        }
    }
}
复制代码

在上面的MyWorker实例中,继承了Worker 并且重写了doWork()方法,需要注意的是doWork()方法是有返回值Worker.Result的,可以在任务执行成功是返回 Worker.Result.SUCCESS ,在任务执行出现异常时返回 Worker.Result.FAILURE doWork()方法的返回值主要有三种 1、 Worker.Result.SUCCESS 表示任务执行成功

2、 Worker.Result.FAILURE 表示任务执行失败

3、 Worker.Result.RETRY 通知WorkManager之后再尝试执行该任务

WorkRequest

WorkRequest要指定执行任务的Worker,也可以给WorkRequest加一些规则,比如说什么时候执行任务,任务执行一次还是多次,每一个WorkRequest都有一个自动产生的唯一ID,可以根据唯一ID获取对应任务的状态以及是否取消对应的任务。如下图WorkRequest有两个实现类如下图:

WorkManager完全解析+重构轮询系统
1、OneTimeWorkRequest

任务只执行一次

OneTimeWorkRequest myWorkRequest =
        new OneTimeWorkRequest.Builder(MyWorker.class)
    .build();
    //将上面定义的MyWorker加入到OneTimeRequest.Builder方法中
WorkManager.getInstance().enqueue(myWorkRequest);//获取WorkManager实例并将WorkRequest进队
复制代码

2、PeriodicWorkRequestPeriodicWorkRequest重复执行任务,直到被取消才停止。首次执行是任务提交后立即执行或者满足所给的 Constraints条件。以后执行都会根据所给的时间间隔来执行。注意任务的执行可能会有延时,因为WorkManager会根据OS的电量进行优化。 假如设置的Periodic Work是24小时执行一次,有可能根据电池优化策略执行的过程如下:

1     | Jan 01, 06:00 AM
     2     | Jan 02, 06:24 AM
     3     | Jan 03, 07:15 AM
     4     | Jan 04, 08:00 AM
     5     | Jan 05, 08:00 AM
     6     | Jan 06, 08:02 AM
复制代码

由上面的执行时间可以看出,PeriodicWorkRequest并不是准确的按照24小时来执行,会有一定的时间延迟。因此如果需要准确的间隔时间来执行任务的话不能使用PeriodicWorkRequest。

Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
PeriodicWorkRequest build = new PeriodicWorkRequest.Builder(MyWorker.class, 25, TimeUnit.MILLISECONDS)
           .addTag(TAG)
           .setConstraints(constraints)
           .build();

WorkManager instance = WorkManager.getInstance();
if (instance != null) {
          instance.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, build);
}
复制代码

Constraints

可以给任务加一些运行的Constraints条件,比如说当设备空闲时或者正在充电或者连接WiFi时执行任务。

Constraints myConstraints = new Constraints.Builder()
    .setRequiresDeviceIdle(true)
    .setRequiresCharging(true)
    // Many other constraints are available, see the
    // Constraints.Builder reference
     .build();
OneTimeWorkRequest myWork =
                new OneTimeWorkRequest.Builder(CompressWorker.class)
     .setConstraints(myConstraints)
     .build();
复制代码

WorkManager

WorkManager管理WorkRequest队列。并根据设备和其他条件选择执行的具体方式。在大部分情况在如果没有给队列加Contraints,WorkManager会立即执行任务。

WorkManager.getInstance().enqueue(myWork);
复制代码

如果要检查任务的执行状态可以通过获取WorkInfo,WorkInfo在WorkManager里面的 LiveData<WorkInfo> 中。下面是判断任务是否结束的方式。

WorkManager.getInstance().getWorkInfoByIdLiveData(myWork.getId())
    .observe(lifecycleOwner, workInfo -> {
        // Do something with the status
        if (workInfo != null && workInfo.getState().isFinished()) {
            // ...
        }
    });
复制代码

取消任务执行

通过任务的ID可以获取任务从而取消任务。任务ID可以从WorkRequest中获取。

UUID compressionWorkId = compressionWork.getId();
WorkManager.getInstance().cancelWorkById(compressionWorkId);
复制代码

注意并不是所有的任务都可以取消,当任务正在执行时是不能取消的,当然任务执行完成了,取消也是意义的,也就是说当任务加入到ManagerWork的队列中但是还没有执行时才可以取消。

WorkManager多任务调度

有时候可能有很多任务需要执行,并且这些任务之前可能有先后顺序或者某些依赖关系,WorkManager提供了很好的方式。 1、先后顺序执行单个任务 比如说有三个任务workA,workB,workC,并且执行顺序只能时workA---->workB---->workC可以用如下的方式处理。

WorkManager.getInstance()
    .beginWith(workA)
    .then(workB)  instance
    .then(workC)
    .enqueue();
复制代码

上面的workA,workB,workC,都是WorkRequest的子类实现对象。WorkManager会根据上面的先后顺序来执行workA,workB,workC,,但是如果执行过程中三个任务中有一个失败,整个执行都会结束。并且返回 Result.failure()2、先后顺序执行多个任务列 有时候可能要先执行一组任务,然后再执行下一组任务,可以使用下面的方式来完成。

WorkManager.getInstance()
    // First, run all the A tasks (in parallel):
    .beginWith(Arrays.asList(workA1, workA2, workA3))
    // ...when all A tasks are finished, run the single B task:
    .then(workB)
    // ...then run the C tasks (in any order):
    .then(Arrays.asList(workC1, workC2))
    .enqueue();
复制代码

3、多路径先后执行上面两种方式都是单路径执行,可以实现更加复杂的多路径执行方式,使用 WorkContinuation.combine(List<OneTimeWorkRequest>) 如下图要实现的执行方式:

WorkManager完全解析+重构轮询系统
WorkContinuation chain1 = WorkManager.getInstance()
    .beginWith(workA)
    .then(workB);
WorkContinuation chain2 = WorkManager.getInstance()
    .beginWith(workC)
    .then(workD);
WorkContinuation chain3 = WorkContinuation
    .combine(Arrays.asList(chain1, chain2))
    .then(workE);
chain3.enqueue();
复制代码

未完待续........下周末来重构之前的轮询框架: juejin.im/post/5c2e0e…


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

疯狂科学家大本营

疯狂科学家大本营

Bei Er Fei Ao Er / 本书翻译组 译、黄晓庆 周宇煜 张为民 审译 / Science Press / 2012-1-5 / 48.00元

美国最棒的创意工场不是贝尔实验室,不是硅谷,也不是麻省理工学院的媒体实验室,而是由五角大楼领导的绝密军事机构DARPA——国防高级研究计划局。DARPA是由美国前总统艾森豪威尔建立的军事部门,创建的目的是为了回应苏联的太空计划。 虽然DARPA属于政府机构,但是没有冷冰 冰的氛围和官僚做派,那里的科学家偏爱牛仔裤和运动鞋。不过他们最爱的还是在各个领域寻找颠覆性创意。从航空航天、IT,到能源领......一起来看看 《疯狂科学家大本营》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

URL 编码/解码
URL 编码/解码

URL 编码/解码

SHA 加密
SHA 加密

SHA 加密工具