• 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方法运行于分线程,因此该方法内部不能操作界面控件。下面是自定义的工作者代码例子:

    1. public class CollectWork extends Worker {
    2.     private final static String TAG = "CollectWork";
    3.     private Data mInputData; // 工作者的输入数据
    4.     public CollectWork(Context context, WorkerParameters workerParams) {
    5.         super(context, workerParams);
    6.         mInputData = workerParams.getInputData();
    7.     }
    8.     // doWork内部不能操纵界面控件
    9.     @Override
    10.     public Result doWork() {
    11.         String desc = String.format("请求参数包括:姓名=%s,身高=%d,体重=%f",
    12.                 mInputData.getString("name"),
    13.                 mInputData.getInt("height", 0),
    14.                 mInputData.getDouble("weight", 0));
    15.         Log.d(TAG, "doWork "+desc);
    16.         // 这里填详细的业务逻辑代码
    17.         Data outputData = new Data.Builder()
    18.                 .putInt("resultCode", 0)
    19.                 .putString("resultDesc", "处理成功")
    20.                 .build();
    21.         return Result.success(outputData); // success表示成功,failure表示失败
    22.     }
    23. }

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

    1、构建约束条件

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

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

    2、构建输入数据

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

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

    3、构建工作请求

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

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

    4、执行工作请求

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

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

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

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

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

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

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


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

  • 相关阅读:
    快讯|Tubi 有 Rabbit AI 啦
    C++日期和时间编程小结
    TSINGSEE青犀智能分析网关如何助力别墅区域监控智能化信息化发展?
    STM32——触摸屏实验-电阻型触摸屏-M4
    (脑肿瘤分割笔记:六十二)缺失模态下的对抗性联合训练脑肿瘤分割网络
    MD5退出历史舞台你知道吗?
    SQLZOO——SELECT within SELECT Tutorial
    Java中的枚举和注解
    vue.js毕业设计,基于vue.js前后端分离图书购物商城系统设计与实现(H5移动项目)
    GFS分布式文件系统
  • 原文地址:https://blog.csdn.net/aqi00/article/details/127442888