AAC---WorkManager

WorkManager介绍

它的主要作用则是管理在后台工作的任务,即使APP没有启动,它也能保证任务可以被执行。这样的好处可以提高应用的效率 , 降低耗电量 , 同时通过约束的方式来限制功能的上传。

WorkManager机制

在5.0以上的版本WorkManager会通过JobScheduler或者Firebase的JobDispatcher来实现,而在5.0以下的版本,则会通过AlarmManager来实现

它有以下好处:

  1. 支持异步的单次、定时的任务
  2. 支持网络条件、存储空间、充电状态等条件的约束
  3. 支持复杂的并行的链式任务
  4. 某个Work Request的输出作为下一个Work Request的输入
  5. 仅支持Target 14以上的API
  6. 遵循系统的健康
  7. 支持LiveData将请求的状态同步到UI

但是WorkManager仍然无法代替线程池、AsyncTask,例如以下的例子都可以使用WorkManager:上传日志,实现图片的滤镜并且保存图片,定期从网络同步本地数据。

使用WorkManager

  1. 导入WorkManager
    在app的Module中导入Kotlin的WorkManager。而目前的版本号已经到了1.0.0-alpha13
dependencies {
    implementation "android.arch.work:work-runtime-ktx:$versions.work"
}
  1. 创建Worker
    创建一个类,继承自Worker,并且实现doWork函数,返回任务执行的结果,并且在任务中可以携带数据返回结果 , 而任务结果可以在LiveData中获取。
class TestWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {
    private val TAG by lazy { TestWorker::class.java.simpleName }
    private val KEY_EXCEPTION by lazy { "KEY_EXCEPTION" }
    private val KEY_SUCCESS by lazy { "KEY_SUCCESS" }
    override fun doWork(): Result {
        return try {
            Log.e(TAG, "Worker Do Work")
            val successData = Data.Builder().putString(KEY_SUCCESS, "Success").build()
            Result.success(successData)
        } catch (exception: Exception) {
            val exceptionData = Data.Builder().putString(KEY_EXCEPTION, "Exception :${exception.message}").build()
            Result.failure(exceptionData)
        }
    }
}
  1. 将Worker加入队列中
    在创建完任务后,需要将该任务加入WorkManager的队列中。在以下代码中,创建了只执行一次的任务OneTimeWorkRequest,并且携带了输入的参数setInputData,创建完后,就可以将它插入到WorkManager的队列中等待执行。
val inputData = Data.Builder().putString("KEY_INPUT", "input data").build()
val workRequest = OneTimeWorkRequest.Builder(TestWorker::class.java).setInputData(inputData).build()
WorkManager.getInstance().enqueue(workRequest)

通过PeriodicWorkRequest创建的任务,是会定期执行的,需要传入定期的时间即可

创建链式任务

当某些任务具有依赖关系时候(如A依赖B完成的结果,B又依赖C完成的结果),则需要使用链式任务。


链式任务

可以通过WorkManager.beginWith来开始执行任务,并且通过then来将后续的任务链接上。并且可以将前一个任务的输出作为后一个任务的输入。

val workA = OneTimeWorkRequest.Builder(TestWorker::class.java).build()
val workB = OneTimeWorkRequest.Builder(BlurWorker::class.java).build()
val workC = OneTimeWorkRequest.Builder(CleanupWorker::class.java).build()
WorkManager.getInstance().beginWith(workA).then(workB).then(workC).enqueue()

doWork中通过getInputData来获取上一个任务传递的参数

class BlurWork extends Worker {

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

        @NonNull
        @Override
        public ListenableWorker.Result doWork() {
            getInputData().getKeyValueMap().get("Key");
            return Result.success();
        }
    }

如果只允许单独的任务存在的话,则需要通过beginUniqueWork来开启任务。当存在重复的任务时,会采用传入的ExistingWorkPolicy来对已存在的任务进行策略处理。

WorkManager.getInstance().beginUniqueWork("workName",ExistingWorkPolicy.REPLACE,workA).enqueue()

多链式任务

例如有任务需要等待多个链式任务完成的话 , 则可以通过WorkManager来实现.

多个链式任务

通过以下方式来完成链式任务的执行.

WorkContinuation chain1 = WorkManager.getInstance(myContext)
        .beginWith(workA)
        .then(workB);
    WorkContinuation chain2 = WorkManager.getInstance(myContext)
        .beginWith(workC)
        .then(workD);
    WorkContinuation chain3 = WorkContinuation
        .combine(Arrays.asList(chain1, chain2))
        .then(workE);
    chain3.enqueue();
    

使用LiveData监听任务状态

在任务执行的过程中,可以通过LiveData来监听任务的状态,所有的任务都具有这几种状态:

  • BLOCKED:阻塞
  • CANCELLED:被取消
  • ENQUEUED:入队列
  • FAILED:失败
  • RUNNING:正在运行
  • SUCCEEDED:运行成功
  1. 通过addTag设置任务的Tag
val workRequest = OneTimeWorkRequest.Builder(TestWorker::class.java).addTag("workRequest").build()
WorkManager.getInstance().enqueue(workRequest)
  1. 1.0.0-alpha10版本中,还可以通过WorkManager.getInstance().getStatusesByTagLiveData()获取对应的Worker的Status。

1.0.0-alpha13版本中,已经没有该函数了,已经替换成getWorkInfosByTagLiveData,而获取的也就是WorkInfo,也差不多。

val liveData = WorkManager.getInstance().getWorkInfosByTagLiveData("workRequest");
liveData.observe(this, Observer {
     if (it[0].state.isFinished) {
      // 任务已经完成
     } else {
      // 任务未完成
     }
})

而获取任务结果的话 , 可以通过

 WorkManager.getInstance(getContext()).getWorkInfoByIdLiveData(uuid)
.observe(getOwnerActivity(), new Observer<WorkInfo>() {
            @Override
            public void onChanged(WorkInfo workInfo) {
                // 获取任务执行结果
                workInfo.getOutputData();
            }
        });

取消任务

在WorkManager中也可以取消:

// 根据TAG取消所有任务
WorkManager.getInstance().cancelAllWorkByTag()
// 根据UniqueWorkName取消任务
WorkManager.getInstance().cancelUniqueWork()
// 根据uuid取消任务
WorkManager.getInstance().cancelWorkById()

增加任务约束

当某个任务需要在某个条件时开始,可以在任务的Builder中添加约束(Constraint)。

// 创建正在充电的约束
val constraints = Constraints.Builder()
        .setRequiresCharging(true)
        .build()

//  将约束添加到请求中
val save = OneTimeWorkRequestBuilder<BlurWorker>()
        .setConstraints(constraints)
        .addTag(TAG_OUTPUT)
        .build()
continuation = continuation.then(save)

// 启动任务
continuation.enqueue()

新增加进度同步

在最新的2.3.4版本的WorkManager中新增任务进度同步的接口.

public class ProgressWorker extends Worker {

        private static final String PROGRESS = "PROGRESS";
        private static final long DELAY = 1000L;

        public ProgressWorker(
            @NonNull Context context,
            @NonNull WorkerParameters parameters) {
            super(context, parameters);
            // 设置初始化进度为0
            setProgressAsync(new Data.Builder().putInt(PROGRESS, 0).build());
        }

        @NonNull
        @Override
        public Result doWork() {
             //Do something
            ...
            // 设置进度为100
            setProgressAsync(new Data.Builder().putInt(PROGRESS, 100).build());
            return Result.success();
        }
    }

LiveData中获取到该进度

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

推荐阅读更多精彩内容

  • WorkManager架构组件是用来管理后台工作任务。这个时候你可能会奇怪了Android不是已经 有很多管...
    tuacy阅读 6,470评论 4 14
  • 1、概述 在 I / O '18中,Google发布了Android Jetpack。它是一组库,工具和架构指南,...
    高丕基阅读 7,501评论 1 12
  • 5月8号, I/O大会上推出了Architeture新组件WorkManager。 由于Android版本的不断更...
    SYfarming阅读 1,531评论 0 3
  • 1.昨晚做了咖啡冥想后非常安静的睡着了,然后做了一个很美好的梦,梦见自己变成了一个漂亮的女孩儿,穿着雪白的羽绒服,...
    照法阅读 127评论 0 0
  • 在墁坪 我见到一对年轻的护林夫妻 带着两只可爱的小犬 守着一条沟里少有的寂静 我是个远道而来的客人 找寻三十年前遗...
    甘肃子溪阅读 85评论 0 0