Android开发笔记(一百八十八)工作管理器WorkManager

Posted aqi00

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android开发笔记(一百八十八)工作管理器WorkManager相关的知识,希望对你有一定的参考价值。

android11不光废弃了AsyncTask,还把IntentService一起废掉了,对于后台的异步服务,官方建议改为使用工作管理器WorkManager。
其实除了IntentService之外,Android也提供了其它后台任务工具,例如工作调度器JobScheduler、闹钟管理器AlarmManager等等。当然这些后台工具的用法各不相同,徒增开发者的学习时间而已,于是乎谷歌索性把它们统一起来,在Jetpack库中推出了工作管理器WorkManager。这个WorkManager的兼容性很强,对于Android6.0或更高版本的系统,它通过JobScheduler完成后台任务;对于Android6.0以下版本的系统(不含Android6.0),通过AlarmManager和广播接收器组合完成后台任务。不过无论采取哪种方案,后台任务最终都是由线程池Executor执行。
因为WorkManager来自Jetpack库,所以使用之前要修改build.gradle,增加下面一行依赖配置:

implementation 'androidx.work:work-runtime:2.4.0'

接着定义一个处理后台业务逻辑的工作者,该工作者继承自Worker抽象类,就像异步任务需要从IntentService派生而来那样。自定义的工作者必须实现构造方法,并重写doWork方法,其中构造方法可获得外部传来的请求数据,而doWork方法处理具体的业务逻辑。特别要注意,由于doWork方法运行于分线程,因此该方法内部不能操作界面控件。下面是自定义的工作者代码例子:

public class CollectWork extends Worker 
    private final static String TAG = "CollectWork";
    private Data mInputData; // 工作者的输入数据

    public CollectWork(Context context, WorkerParameters workerParams) 
        super(context, workerParams);
        mInputData = workerParams.getInputData();
    

    // doWork内部不能操纵界面控件
    @Override
    public Result doWork() 
        String desc = String.format("请求参数包括:姓名=%s,身高=%d,体重=%f",
                mInputData.getString("name"),
                mInputData.getInt("height", 0),
                mInputData.getDouble("weight", 0));
        Log.d(TAG, "doWork "+desc);
        // 这里填详细的业务逻辑代码
        Data outputData = new Data.Builder()
                .putInt("resultCode", 0)
                .putString("resultDesc", "处理成功")
                .build();
        return Result.success(outputData); // success表示成功,failure表示失败
    

然后在活动页面中构建并启动工作任务,详细过程主要分为下列四个步骤:

1、构建约束条件

该步骤说明在哪些情况下才能执行后台任务,也就是运行后台任务的前提条件,此时用到了约束工具Constraints,约束条件的构建代码示例如下:

// 1、构建约束条件
Constraints constraints = new Constraints.Builder()
        //.setRequiresBatteryNotLow(true) // 设备电量充足
        //.setRequiresCharging(true) // 设备正在充电
        .setRequiredNetworkType(NetworkType.CONNECTED) // 已经连上网络
        .build();

2、构建输入数据

该步骤把后台任务需要的输入参数封装到一个数据对象中,此时用到了数据工具Data,输入数据的构建代码示例如下:

// 2、构建输入数据
Data inputData = new Data.Builder()
        .putString("name", "小明")
        .putInt("height", 180)
        .putDouble("weight", 80)
        .build();

3、构建工作请求

该步骤把约束条件、输入数据等请求内容组装起来,此时用到了工作请求工具OneTimeWorkRequest,工作请求的构建代码示例如下:

// 3、构建一次性任务的工作请求
String workTag = "OnceTag";
OneTimeWorkRequest onceRequest = new OneTimeWorkRequest.Builder(CollectWork.class)
        .addTag(workTag) // 添加工作标签
        .setConstraints(constraints) // 设置触发条件
        .setInputData(inputData) // 设置输入参数
        .build();
UUID workId = onceRequest.getId(); // 获取工作请求的编号

4、执行工作请求

该步骤生成工作管理器实例,并将第3步的工作请求对象加入到管理器的执行队列,由管理器调度并执行请求任务,执行工作的代码例子如下所示:

// 4、执行工作请求
WorkManager workManager = WorkManager.getInstance(this);
workManager.enqueue(onceRequest); // 将工作请求加入执行队列

当然,工作管理器不单拥有enqueue,还有其它的调度方法,常用的几个方法说明如下:
enqueue:将工作请求加入执行队列。
cancelWorkById:取消指定编号的工作。其中工作编号为第3步getId方法返回的workId。
cancelAllWorkByTag:取消指定标签的所有工作。其中工作标签为第3步设置的workTag。
cancelAllWork:取消所有工作。
getWorkInfoByIdLiveData:获取指定编号的工作信息。
鉴于后台任务是异步执行着的,若想知晓工作任务的处理结果,就得调用getWorkInfoByIdLiveData方法,获取工作信息并实时监听它的运行情况。此时工作结果的查询代码示例如下:

// 获取指定编号的工作信息,并实时监听工作的处理结果
workManager.getWorkInfoByIdLiveData(workId).observe(this, workInfo -> 
    if (workInfo.getState() == WorkInfo.State.SUCCEEDED)  // 工作处理成功
        Data outputData = workInfo.getOutputData(); // 获得工作信息的输出数据
        int resultCode = outputData.getInt("resultCode", 0);
        String resultDesc = outputData.getString("resultDesc");
        String desc = String.format("工作处理结果为:resultCode=%d,resultDesc=%s",
                resultCode, resultDesc);
        tv_result.setText(desc);
    
);

至此,工作管理器的任务操作步骤都过了一遍。眼尖的读者可能发现,第3步的工作请求类名叫做OneTimeWorkRequest,读起来像是一次性工作。其实工作管理器不仅支持设定一次性工作,也支持设定周期性工作,此时用到的工作请求名叫PeriodicWorkRequest,它的构建代码示例如下:

// 3、构建周期性任务的工作请求。周期性任务的间隔时间不能小于15分钟
String workTag = "PeriodTag";
PeriodicWorkRequest periodRequest = new PeriodicWorkRequest.Builder(
        CollectWork.class, 15, TimeUnit.MINUTES)
        .addTag(workTag) // 添加工作标签
        .setConstraints(constraints) // 设置触发条件
        .setInputData(inputData) // 设置输入参数
        .build();
UUID workId = periodRequest.getId(); // 获取工作请求的编号

最后在活动页面中集成工作管理器,运行测试App后点击启动按钮,观察到任务执行结果如下图所示,可见成功获知了后台工作的运行情况。


点此查看Android开发笔记的完整目录

以上是关于Android开发笔记(一百八十八)工作管理器WorkManager的主要内容,如果未能解决你的问题,请参考以下文章

Android开发笔记(一百八十八)工作管理器WorkManager

Android开发笔记(一百八十六)管理SQLite的利器——应用检查器App Inspection

Android开发笔记(一百八十六)管理SQLite的利器——应用检查器App Inspection

Android开发笔记(一百八十六)管理SQLite的利器——应用检查器App Inspection

Android开发笔记(一百八十六)管理SQLite的利器——应用检查器App Inspection

Android开发笔记(一百八十七)利用估值器实现弹幕动画