Android JetPack-WorkManager详解

WorkManager

WorkManager是Google最新的后台任务调度解决方案,Google计划2020年11月1日开始全面统一在Android上使用WorkManager处理后台任务的调度处理工作

在后台,WorkManager根据以下条件使用基础的作业调度服务:


不同版本的调度

WorkManager的优势

  • 最高向后兼容到 API 14
    • 在运行 API 23 及以上级别的设备上使用 JobScheduler
    • 在运行 API 14-22 的设备上结合使用 BroadcastReceiver 和 AlarmManager
  • 添加网络可用性或充电状态等工作约束,根据添加的约束条件智能的启动后台任务
  • 调度一次性或周期性异步任务
  • 监控和管理计划任务
  • 将任务链接起来,可以给多个任务进行串行、并行调度,甚至多个链多个链的串行并行
  • 确保任务执行,即使应用或设备重启也同样执行任务,依赖于room的持久化实现
  • 遵循低电耗模式等省电功能,更省电

现在,WorkManager库已经成熟,并且极大的减轻了Android开发的工作量,还更加省电、可靠、性能优越

但是要注意WorkManager适用于及时性不高的任务,一些高及时性的场景不要使用,比如你的订单创建那就要立马发送请求,及时响应结果

假如说你的订单是离线(也就是没有网络)也需要创建成功,等网络再进行提交,那么这种场景就比较适合使用WorkManager,能极大减少工作量 ,还能一定程度上保证订单不会丢失

之所以WorkManager能进程退出、奔溃、重启机器情况下也能保证完成提交给系统的延时任务是依赖与数据的持久化

可以看到文件、数据库的使用,这是workmanager自己创建的

以后要是吹WorkManager源码分析、底层实现分析的牛逼

主要就拿JobScheduler、JobService、sqlite(room)、sp、GreedyScheduler、BroadcastReceiver、Alarm、线程池、Handler、LifecycleService(Androidx)吹

围观一下数据库


WorkManager DB
表结构
image.png

使用

使用比较简单,首先添加必要的依赖注册初始化

//依赖库
 def work_version = "2.3.0-alpha01"
 implementation "androidx.work:work-runtime:$work_version"
//清单文件
 
//application
public class Myapplication extends Application implements Configuration.Provider {

    @Override
    public void onCreate() {
        super.onCreate();
        Configuration myConfig = new Configuration.Builder()
                .setMinimumLoggingLevel(android.util.Log.VERBOSE)
                .build();
        WorkManager.initialize(getBaseContext(), myConfig);
    }
    @NonNull
    @Override
    public Configuration getWorkManagerConfiguration() {
        return new Configuration.Builder()
                .setMinimumLoggingLevel(android.util.Log.INFO)
                .build();
    }
}

如果不在manifest文件注册application中初始化,可能会报以下错

WorkManager is not initialized properly. You have explicitly disabled WorkManagerInitializer in your manifest, have not manually called WorkManager#initialize at this point, and your Application does not implement Configuration.Provider

WorkManager is already initialized. Did you try to initialize it manually without disabling WorkManagerInitializer? See WorkManager#initialize(Context, Configuration) or the class levelJavadoc for more information.

另外要注意:

WorkManager.getInstance()调用不要在application中的attachBaseContext方法调用

对于老项目要使用的话,首先要对项目进行迁移androidX,Android studio已经可以一键迁移,修改buildToolsVersion 28以上、gradle3.2以上

classpath 'com.android.tools.build:gradle:3.2.0+'
android.useAndroidX=true
android.enableJetifier=true
迁移AndroidX

剩下的代码基本分为三步
1、创建
2、设置约束条件
3、执行

当然 中间可以观察者模式调用,观察调用进度、数据,也可以暂停、取消操作

下面看看代码使用WorkManager

创建WorkRequest 并将其加入队列

  • 一次性任务 OneTimeWorkRequest

    执行工作器的确切时间还取决于 WorkRequest 中使用的Constraints约束和系统优化。WorkManager 经过设计,在满足这些约束的情况下提供可能的最佳行为


        
        //任务约束条件
        Constraints constraints = new Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED)//联网状态
                .setRequiresBatteryNotLow(true)//非低电量
                .setRequiresDeviceIdle(true)//设备空闲
                .setRequiresStorageNotLow(true)//存储空间足够
                .setRequiresCharging(true)//充电状态
                .setTriggerContentMaxDelay(20, TimeUnit.DAYS)//延时20天后执行
                .build();

        //定义传入到任务中的数据
        Data inputData = new Data.Builder().putString("chris", "数据").build();

        //一次性任务
        OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(MainWorker.class)
                .setInputData(inputData)
                .setConstraints(constraints)
                .build();
  • 重复周期性任务 PeriodicWorkRequest
    最小周期不能低于15分钟,如果设置小于15分钟,也是按15分钟的周期运行
    日志会打印:Interval duration lesser than minimum allowed value; Changed to 900000"
     //一天一次周期任务
       PeriodicWorkRequest saveRequest =
               new PeriodicWorkRequest.Builder(MainWorker.class, 1, TimeUnit.DAYS)
                       .setConstraints(constraints)
                       .build();
  • woker任务执行
public class MainWorker extends Worker {
    private static final String TAG = "MainWorker";

    public MainWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    //这个方法是在子线程执行的
    @NonNull
    @Override
    public Result doWork() {
        //上传,下载,同步数据
        Log.e(TAG, "执行了");
        //获取mainActivity传入进来的数据
        String data = getInputData().getString("chris");
        Log.e(TAG, "中取到了数据" + data);
        //把任务中的数据回传到activity中
        Data outputData = new Data.Builder().putString("name", "chris").build();

        //进度
        setProgressAsync(new Data.Builder().putInt("Progress",78).build());

        return Result.success(outputData);
    }
}

  • 加入队列执行
 WorkManager.getInstance()
                .beginUniqueWork("unique",
                        ExistingWorkPolicy.REPLACE//设置任务不重复
                        , request)
                .enqueue();
  • 观察工作状态接收数据
 //接收任务中回来的数据、进度
        WorkManager.getInstance().getWorkInfoByIdLiveData(request.getId())
                .observe(this, new Observer() {
                    @Override
                    public void onChanged(WorkInfo workInfo) {
                        //获取进度
                        Data progress = workInfo.getProgress();
                        int Progress = progress.getInt("Progress", 0);

                        //获取数据
                        String name = workInfo.getOutputData().getString("name");
                        Log.i(TAG, "取到了任务回传的数据" + name);

                    }
                });

  • 任务的取消、暂停
 //取消所有
        WorkManager.getInstance(this).cancelAllWork();
        //取消某一个 如saveRequest
        WorkManager.getInstance().cancelWorkById(saveRequest.getId());

        //按标记取消 WorkRequest会取消所有具有此标记的工作
        WorkManager.getInstance().cancelAllWorkByTag(request.getStringId());

        //取消所有未完成的工作的工作链的名字:unique
        WorkManager.getInstance(this).cancelUniqueWork("unique");


有高级玩法,比如取消当前的执行任务并将其 REPLACE 为新工作链

  • 任务链

多任务组合一个任务链

 WorkManager.getInstance(this)

                //request,request2并发执行
                .beginWith(Arrays.asList(request, request2))
                //request1 request2顺序执行
                .then(request1).then(request2)
                .then(Arrays.asList(request1, request2))
                .enqueue();

多任务链合并一个任务链

 //两个任务链
        WorkContinuation begin = WorkManager.getInstance(this).beginWith(Arrays.asList(request, request2));
        WorkContinuation then = WorkManager.getInstance(this).beginWith(request).then(request1);

        //多任务链合并,
        WorkContinuation thenEnd = WorkContinuation.combine(Arrays.asList(begin, then)).then(request);

        //多任务链执行
        thenEnd.enqueue();

如果需要创建一个唯一单次工作链可以使用 WorkManager.beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest 代替 beginWith()

   //创建一个唯一周期重复工作链     WorkManager.getInstance(base).enqueueUniquePeriodicWork(TAG_Unique, ExistingPeriodicWorkPolicy.REPLACE, mPeriodicWorkRequest);

adb 查看自己app的work


adb shell am broadcast -a "androidx.work.diagnostics.REQUEST_DIAGNOSTICS"  appPackageName

执行adb广播之后,logcat过滤自己app的日志显示所有

你可能感兴趣的:(Android JetPack-WorkManager详解)