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"
//清单文件
 <provider
            android:name="androidx.work.impl.WorkManagerInitializer"
            android:authorities="${applicationId}.workmanager-init"
            android:directBootAware="false"
            android:exported="false"
            android:multiprocess="true"
            tools:node="remove"
            tools:targetApi="n" />
//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<WorkInfo>() {
                    @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的日志显示所有

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342