WorkManager

WorkManager可以用来执行一个在特定条件下触发执行的延时任务。比如我设置触发条件是,手机有网络连接的时候才会触发。当我们断网的时候打开app,我们的任务不会立即执行,当手机联网之后才会触发。
这样我们就可以利用WorkManager轻松实现某些条件下触发的延时任务。

引入

在项目中引入WorkManager包

implementation "android.arch.work:work-runtime:1.0.0-alpha01"
implementation "android.arch.work:work-firebase:1.0.0-alpha01"

使用

首先我们要创建我们的任务类。

ublic class MyWork extends Worker {

    @NonNull
    @Override
    public WorkerResult doWork() {
         //执行任务
        return WorkerResult.SUCCESS;
    }
}

doWork会在条件满足的时候触发。

再来看看怎么定义触发规则并把任务添加到WorkManager中。

Constraints constraints = new Constraints.Builder()//定义触发规则
                .setRequiredNetworkType(NetworkType.CONNECTED)//触发规则是当有络连接的时候执行
                .build();

        Data data = new Data.Builder()//添加数据
                .putString("data","你好")
                .build();

        OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWork.class)//创建WorkRequest
                .setConstraints(constraints)
                .setInputData(data)
                .build();

        WorkManager.getInstance().enqueue(workRequest);//添加到WorkManager去管理任务。
Constraints

用来定义任务的触发条件,网络状态说明:

状态 说明
NOT_REQUIRED 没有要求
CONNECTED 网络连接
UNMETERED 连接无限流量的网络
METERED 连接按流量计费的网络
NOT_ROAMING 连接非漫游网络

除了网络连接的状态还有下面的触发条件可以选择:

setRequiresBatteryNotLow(true)//不在电量不足时执行
setRequiresCharging(true)//在充电时执行
setRequiresStorageNotLow(true)//不在存储容量不足时执行
setRequiresDeviceIdle(true)//在待机状态执行
Data

用来创建要传递给worker的参数,传入方式是键值对。

OneTimeWorkRequest

这个Request说明只会触发一次。如果需要执行周期性任务可以使用PeriodicWorkRequest。

PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest
                          .Builder(MyWorker.class,15, TimeUnit.SECONDS)
                          .setConstraints(constraints)
                          .setInputData(data)
                          .build();

取消任务

UUID workId = workRequest.getId();
WorkManager.getInstance().cancelByWorkId(workId);

Worker接收并返回参数

public class MyWork extends Worker {

    @NonNull
    @Override
    public WorkerResult doWork() {
        String name = getInputData().getString("data", "");//获取数据
        //做些什么
        Data data = new Data.Builder().putString("out","返回点什么").build();
        setOutputData(data);//返回数据
        return WorkerResult.SUCCESS;
    }
}
拿到worker返回的数据

要拿到返回的数据需要利用回调。

WorkManager.getInstance().getStatusById(workRequest.getId())//通过workRequest的id获取
                .observe(this, new Observer() {
                    @Override
                    public void onChanged(@Nullable WorkStatus workStatus) {
                        String data = workStatus.getOutputData().getString("out","");
                        Log.d("MainActivity", data);
                    }
                });

第一个参数是LifecycleOwner,回调同步生命周期,是为了防止我们页面退出之后可能造成的内存泄漏。
我们从第二个回调里面可以拿到返回的数据。

在这里我们要着重注意数据的大小,如果数据太大就会报下面的异常:


对,添加到Data的数据不能大于10KB,本来我也以为是10M(火星换算法10240KB=10KB),但是我的数据才十几KB,怎么会超出范围,然后从源码中发现:



可能作者跟大家开了个玩笑。大家跟着笑就行了。哈哈

链式任务

有些时候任务执行前后顺序会影响到结果,需要顺序执行某些任务,又或者后面的任务需要使用前面任务得出的结果,这个时候我们就可以使用链式任务。
1、ABC先后执行

WorkManager.getInstance().beginWith(A).then(B).then(C).enqueue();

2、A,B没有先后顺序,但是A、B均为C的前驱任务

WorkManager.getInstance().beginWith(A,B).then(C).enqueue();

3、A、B和C、D链式执行,执行完之后在执行E

WorkContinuation workContinuation1 = WorkManager.getInstance().beginWith(A).then(B);
WorkContinuation workContinuation2 = WorkManager.getInstance().beginWith(C).then(D);
WorkContinuation workContinuation3 = WorkContinuation.combine(workContinuation1,workContinuation2).then(E).enqueue();

强大的生命力

WorkManager有着强大的存活能力,当我们断网的时候打开app,这个时候任务没有满足触发条件,退出app(进程没有被清除)。这时候连上网络依然会执行任务。

但是当我们结束进程就会出现下面的情况。
我们进行下面的操作。
1、断开网络
2、打开app,这个时候不会执行
3、杀掉应用进程
4、打开网络,第一次的任务没有执行
5、打开app
然后会发现,任务执行了两次。第一次的执行是第一次运行后,加入了任务队列,但还没有执行的任务。
第二次执行是我们第二次打开,因为满足网络连接条件立即执行。

这是 WorkManager 的另一个特点,一旦发起一个任务,任务是可以保证一定会被执行的,就算退出应用,甚至重启手机都阻止不了他。但可能由于添加了环境约束等原因,它执行的时间是不确定的。
原理我们利用网上的一个图片说明。

当应用正在运行时,它会在当前的进程中启用一个子线程执行。应用没有运行的情况下启用,它则会自己选择一种合适的方式在后台运行。具体是什么方式和 Android 的版本和依赖环境有关


是不是很强大
拜拜~~

你可能感兴趣的:(WorkManager)