Android Jetpack WorkManager初级认识

本篇文章已授权微信公众号guolin_blog(郭霖)独家发布

Workmanager简介

WorkManager是用于使可延期工作入队的库,根据设备API级别和应用程序状态等因素选择适当的方式来运行任务。如果WorkManager在应用程序运行时执行您的任务之一,WorkManager可以在您应用程序进程的新线程中运行您的任务。如果您的应用程序未运行,WorkManager会选择一种合适的方式来安排后台任务 - 具体取决于设备API级别和包含的依赖项,WorkManager可能会使用 JobSchedulerFirebase JobDispatcherAlarmManager

该库可保证在Constraints满足要求后的某个时间执行。WorkManager允许观察工作状态以及创建复杂工作链的能力。

WorkManager支持两种类型的工作:OneTimeWorkRequestPeriodicWorkRequest。您可以使用WorkManager排队请求,如下所示:

基本相关类(不全面):

  • Workerextend抽象的Worker类,在实现的方法执行逻辑操作
  • WorkRequest.Builder:用于构建WorkRequest对象;
  • WorkRequest:单一任务的请求 系统已经实现了两个可以使用的子类
  1. OneTimeWorkRequest:只执行一次工作。
  2. PeriodicWorkRequest :重复性执行工作。这项工作执行多次,直到取消。下一个执行期间会发生间隔;

请注意, 执行可能会被推迟,因为受到Constraints下设置的电池优化,, 息屏,网络 等模式影响。

  • Constraints: 默认情况下,WorkRequests可以立即运行。通过添加Constraints可以对指定对任务运行的状态下进行约束(比如没网络,息屏,电池优化等);使用Constraints.Builder构建Constraints对象 ,并传递给WorkRequest.Builder
  • Data : 用于构建一组持续化可供键值对。

WorkManager 使用

添加依赖:

    //增加workManager管理后台任务
    implementation "android.arch.work:work-runtime:1.0.1"
    implementation "android.arch.work:work-firebase:1.0.0-alpha11"

使用方式

  • 简单使用方式

1 实现Worker :
自定义MainWorker,重写doWork,并返回结果

class MainWorker(context: Context,workerParameters: WorkerParameters) :Worker(context,workerParameters){
    override fun doWork(): Result {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}

2 调用
OneTimeWorkRequest.Builder().build()创建对象WorkRequest,然后将任务放入的WorkManager管理的WorkRequest队列(本次文章中都以OneTimeWorkRequest来写例子 )

val baseWork = OneTimeWorkRequest.Builder(MainWorker::class.java).build()
WorkManager.getInstance().enqueue(baseWork)

这样子简单的使用方式就可以了~~~~

但是如果你要监听数据信息然后获取数据进行逻辑操作呢(数据交互)?

可以看一下下面的使用···:

  • 使用方式2 :监听数据方式

1实现work
这里面inputData.getString("LiveDataTest")是从调用的时候传入进来的数据,ruturn的时候使用Result.success(data) 'data'的数据类型的Data返回的数据可以再output中的键值对获取到

class BtnTwoWorker(context: Context, workerParameters: WorkerParameters) :Worker(context,workerParameters){

    override fun doWork(): Result {
        Log.i("MainWorker","点击${inputData.getString("LiveDataTest")}")
        val data = Data.Builder().putString("LiveDataTest","LiveDataTest修改后的信息---").build()
        return  Result.success(data)
    }
}

2 使用

代码中的第一步构建的就是 步骤一中的LiveDataTest的数据,然后构建work设置setInputData(data ) ,通过WorkManager.getInstance().getWorkInfoByIdLiveData(liveDataWork.id)获取LiveData<WorkInfo>并进行监听数据,在监听数据中可以获取到outputdata的键值对进行逻辑处理。
最后将构建的liveDataWork放入WorkManager中的队列等待运行 WorkManager.getInstance().enqueue(liveDataWork)

 //1 构建 Data数据
 var data = Data.Builder().putString("LiveDataTest","有生命的数据监听··").build()

//2 构建work
  val liveDataWork = OneTimeWorkRequest.Builder(BtnTwoWorker::class.java).setInputData(data).build()

//3 通过work的id获取Status
val status =  WorkManager.getInstance().getWorkInfoByIdLiveData(liveDataWork.id)

//4 监听状态以及数据的变化
//注意一点:这里的监听的时候 状态改变Observer就会跑一遍~~
   status.observe(this, Observer {
   if(it.state == WorkInfo.State.SUCCEEDED){
   mViewModel.data.value = it.outputData.getString("LiveDataTest")
   Log.i("WorkerActivity", it.outputData.getString("LiveDataTest")?:"空")
   }
   Log.i("WorkerActivity",it.state.name)
 Log.i("WorkerActivity","${it.state.isFinished}")
            })
//再放入到WorkManager的队列中
 WorkManager.getInstance().enqueue(liveDataWork)

/////////////////////////////////////////////////////
2019-10-14 16:54:33.951 15770-15770/testview.zhen.com.myapplication I/WorkerActivity: ENQUEUED
2019-10-14 16:54:33.951 15770-15770/testview.zhen.com.myapplication I/WorkerActivity: false
2019-10-14 16:54:33.972 15770-15849/testview.zhen.com.myapplication I/MainWorker: 点击有生命的数据监听··
2019-10-14 16:54:33.975 15770-15800/testview.zhen.com.myapplication I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=fa81ea63-6c23-4d40-a72f-7f0eea3baf91, tags={ testview.zhen.com.myapplication.jetpack.BtnTwoWorker } ]
2019-10-14 16:54:34.000 15770-15770/testview.zhen.com.myapplication I/WorkerActivity: LiveDataTest修改后的信息---
2019-10-14 16:54:34.000 15770-15770/testview.zhen.com.myapplication I/WorkerActivity: SUCCEEDED
2019-10-14 16:54:34.000 15770-15770/testview.zhen.com.myapplication I/WorkerActivity: true

从上面执行过程中看出,回调了Work的两个运行状态RUNNING、SUCCESSESD
至于it.state.isFinished这里面的实现为:

        /**
         * Returns {@code true} if this State is considered finished.
         *
         * @return {@code true} for {@link #SUCCEEDED}, {@link #FAILED}, and * {@link #CANCELLED}
         *         states
         */
        public boolean isFinished() {
            return (this == SUCCEEDED || this == FAILED || this == CANCELLED);
        }

当任务 成功/失败/取消 都是结束~

  • 增加任务约束的使用

1 使用Constraints.Builder()创建并配置Constraints对象
里面的设置信息在API中皆有体现

如下图:
image.png
  • setRequiresBatteryNotLow:是否为低电量时运行

  • setRequiredNetworkType:网络连接设置

  • setRequiresCharging:是否在充电情况下运行

  • setRequiresDeviceIdle:设备是否为空闲

  • setRequiresStorageNotLow:设备可用存储是否不低于临界阈值
    以上方法默认值都是 false

  • 使用方式3 :增加情况限制 Constraints

class DelayWorker(context: Context, workerParameters: WorkerParameters) :Worker(context,workerParameters){

    override fun doWork(): Result {
        Log.i("MainWorker","点击${inputData.getString("delayWork")} --所在线程 ${Thread.currentThread().name}")
        val time = inputData.getString("time")

        val data = Data.Builder().putString("LiveDataTest","LiveDataTest修改后的信息---").build()
        return  Result.success(data)

    }


}
           //1 增加约束条件
            val constrains = Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED)
                    .setRequiresBatteryNotLow(true)
                    .build()
            //2 构建 Data数据
            var data = Data.Builder().putString("delayWork","延时操作~~~").putInt("time",10).build()

            //3 构建workRequest
            val workConstrains =  OneTimeWorkRequest.Builder(DelayWorker::class.java)
                    .setConstraints(constrains)
                    .setInputData(data)
                    .build()
            //4 获取Status监听数据
            val status = WorkManager.getInstance().getWorkInfoByIdLiveData(workConstrains.id)
            status.observe(this, Observer {
                Log.i("WorkerActivity",it?.state?.name)
                if (it?.state!!.isFinished) {
                    Log.e("TestWorker", "Finish")
                }
            })
            //5 添加到equque
            WorkManager.getInstance().enqueue(workConstrains)

////////////////////////////////////////////////////////////////////////////////////
2019-10-14 17:57:28.140 25296-25296/testview.zhen.com.myapplication I/WorkerActivity: ENQUEUED            【------没有连接网络的时候先等待】
2019-10-14 17:57:36.609 25296-25296/testview.zhen.com.myapplication I/WorkerActivity: RUNNING                 【------有网络的时候执行】
2019-10-14 17:57:36.610 25296-25469/testview.zhen.com.myapplication I/MainWorker: 点击延时操作~~~ --所在线程 pool-1-thread-1
2019-10-14 17:57:36.613 25296-25325/testview.zhen.com.myapplication I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=fc71f417-8289-4f8c-a489-4d8699960f3d, tags={ testview.zhen.com.myapplication.jetpack.DelayWorker } ]
2019-10-14 17:57:36.637 25296-25296/testview.zhen.com.myapplication I/WorkerActivity: SUCCEEDED

其它一些使用

  • 取消任务

通过获取WorkRequestID或者TAG 获取到相应的WorkRequest从而

//取消任务 方式1:
WorkManager.getInstance().cancelWorkById(workConstrains.id)
//取消任务 方式2:   (这个方式我取消了但是不知道为什么任务都不会停止) 
//这里传入的参数  true 如果线程执行, 任务应该被打断  false,允许在进行任务, 完成;
//WorkManager.getInstance().getWorkInfoById(workConstrains.id).cancel(true) 


/** 通过在WorkRequestBuilder 设置 TAG 然后获取TAG进行取消任务 **/
 OneTimeWorkRequest.Builder(BtnTwoWorker::class.java)
                    .addTag("TAG")
                    .setInputData(data)
                    .build()

//取消任务 方式2:
 WorkManager.getInstance().getStatusesByTag("TAG")
//取消任务 具有特定标记的所有任务 **TAG可以相同**
 WorkManager.getInstance().cancelAllWorkByTag("TAG") 

多任务高级进阶使用(参考官网)

顺序执行

WorkRequest request1 = new OneTimeWorkRequest.Builder(FooWorker.class).build();
 WorkRequest request2 = new OneTimeWorkRequest.Builder(BarWorker.class).build();
 WorkRequest request3 = new OneTimeWorkRequest.Builder(BazWorker.class).build();
 workManager.beginWith(request1, request2).then(request3).enqueue();

每次调用beginWith(OneTimeWorkRequest)beginWith(List)返回一个WorkContinuation,您可以在上调用 WorkContinuation.then(OneTimeWorkRequest)WorkContinuation.then(List)链接进一步的工作。这允许创建复杂的工作链。例如,要创建这样的链:

image.png

 WorkContinuation continuation = workManager.beginWith(A);
 continuation.then(B).then(D, E).enqueue();  // A is implicitly enqueued here
 continuation.then(C).enqueue();

Note: 完成所有先决条件后,工作才有资格执行。如果其任何先决条件失败或被取消,则该工作将永远不会进行。

  • 任务唯一性
    很多情况下,我们希望在任务队列里,同一个任务只存在一个,避免任务的重复执行,这时候可以用到 beginUniqueWork 这个方法:
WorkManager.getInstance()
        .beginUniqueWork("onlyOne", ExistingWorkPolicy.KEEP, work)
        .enqueue()

三个参数 唯一名字、 冲突的处理方式、OneTimeWorkRequest的任务。
冲突的方式enum类型:

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

推荐阅读更多精彩内容