通常来说,我们可以把所有的后台任务按照任务紧迫性(是马上需要执行的任务/还是可以缓期执行的任务)和任务重要性(是确保一定要被执行的任务/还是最好能够执行的任务)进行四象限的划分。通常来说对于非确保一定要执行的任务,无论时间是否紧迫,我们都可以使用ThreadPool来完成这个任务。对于那些比较重要的又时间紧迫的任务,我们一般会使用Foreground Service来完成这个操作。比较有有意思的是最后一个象限:那些希望确保可以被执行但是又可以接受延期执行的任务。这些任务可以使用JobScheduler/JobDispatcher/AlarmManager/BroadcastReceivers来完成。WorkManager也刚好是用来解决这一类的问题的。
下面是WorkManager的一些突出特点:
-
确保可以被执行,并且可以设置执行的限定条件(例如仅仅在有网络连接的时候才进行图片的上传)
-
同样受到系统后台任务的限制管理(如APP进入Doze Mode的时候,任务不会被执行)
-
向后兼容;无论是否集成了Google Play Service服务,都是向后兼容的
-
任务可查询;如论当下在执行什么任务,都是可以直接查询获取到任务状态信息的(例如正在运行的状态是什么,结果是成功还是失败了)
-
任务可串联;例如执行任务A之前需要任务B或者C先进行完成
-
任务伺机执行:在条件满足的时候会尽快尝试触发任务的执行,不需要等待JobScheduler的唤醒,也不会需要等待JobScheduler进行批量任务处理的才被执行
WorkManager中的核心类有:
-
Worker:这个类是真正干活的,工作逻辑都在这里面
-
WorkRequest:
-
OneTimeWorkRequest:只执行一次的任务请求
-
PeriodicWorkRequest:重复执行的任务请求
举个例子:图片上传的后台任务是如何执行的。下面是上传图片的Worker示例:
其中uploadPhoto是执行在后台线程的,返回值可以是成功或者失败,还可以是重试,这意味着告诉系统这个任务需要后面找机会重新执行。有了上面那些基础,接下去就只需要利用Worker创建对应的WorkRequest,并并添加到WorkManager的执行队列中就好了。
正常情况下,放到任务队列中的任务会被立马执行,可是如果遇到网络连接失败的情况,这样就会执行失败。此时我们就可以通过添加限定执行条件来达到优化的目的,例如设置限定只在网络连接成功的时候才进行任务的执行。
有了上面的任务触发逻辑之后,那么如何做任务的监听呢?例如正在处理过程中显示一个进度圈,处理成功的时候消失进度等等。我们可以使用如下演示的范例来监听任务的执行状态。
LiveData
是Google开发的一个感知生命周期的架构组件。使用这个组件来hook监听request任务的WorkStatus
。在WorkStatus里面有任务的id和status,其中status有6种状态,分别是ENQUEUED
,RUNNING
,SUCCEEDED
,FAILED
,BLOCKED
,CANCELLED
。
通常来说,上传任务真正被执行之前,我们会对数据做一次压缩,因为每一个任务都需要在后台进行,并且需要保证执行顺序。我们可以使用下面的示例方式,先进行压缩,成功之后,再进行上传。
只所以可以类似上面那样写,是因为每一步任务返回的都是WorkContinuation
,使用它可以对不同的任务进行串联。
如果想要多项任务并发执行,可以同时建立多个WorkRequest,一起交给WorkManager进行执行(根据CPU核心数和架构的不同,并发数量有所差异)。
我们再把任务链设置的更加复杂一点,例如图片要先分别经过不同的滤镜处理,之后再进行压缩,最后才可以上传,那么使用WorkManager该如何实行呢?
任务之间如何进行数据的传递呢?在介绍这个之前,我们需要了解下什么叫做MapReduce。例如,我们想要从三本书里面找出使用最多的词语,先把所有词语都进行计算一遍,然后对词语的使用次数进行排序,最后才可以找出使用最多的词语,我们把这个行为叫做MapReduce。
使用WorkManager的输入和输出数据具备如下的特点:
-
简单的KEY-VALUE
-
KEY都是String类型的
-
VALUE可以是基础数据类型和String
-
数据本身已经做了序列化处理
-
限定10KB大小以内
我们使用如下的方式进行输入的数据传递,构造一个map类型的Data,通过WorkManager的setInputData()
给Worker进行传输数据。
接下去Worker可以通过getInputData()
来获取到输入的数据。
一般来说,我们会需要把处理的结果进行返回,那么使用setOutputData()
来完成这个操作就可以了
有意思的事情是,在任务链中,输出的数据一般就是下一个任务的输入。那么当某个环节的一个任务是由多个任务的输出构成的时候,改如何处理呢?
为了解决这个问题,我们需要了解InputMergers
,顾名思义,它是用来合并多个输入数据变成一个的。一般来说有两种合并实现的方式(也可以自己自定义)
OverwritingInputMerger
(系统默认):按照输入数据的先后顺序,相同KEY会被覆盖,不同的KEY内容会被保留
ArrayCreatingInputMerger
:相同KEY的VALUE值进行合并,需要确保VALUE是相同数据类型的,否者会出现异常
想要取消一个任务,只需要调用cancelWorkById()
就好了,但是需要注意的是,这个方法只是尽力而为,因为相关想要取消的任务有可能已经在运行,也有可能已经执行结束了。
6)Tags
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(资料价值较高,非无偿)
总结:
面试是一个不断学习、不断自我提升的过程,有机会还是出去面面,至少能想到查漏补缺效果,而且有些知识点,可能你自以为知道,但让你说,并不一定能说得很好。
有些东西有压力才有动力,而学到的知识点,都是钱(因为技术人员大部分情况是根据你的能力来定级、来发薪水的),技多不压身。
附上我的面试各大专题整理: 面试指南,满满的都是干货,希望对大家有帮助!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
知道,但让你说,并不一定能说得很好。
有些东西有压力才有动力,而学到的知识点,都是钱(因为技术人员大部分情况是根据你的能力来定级、来发薪水的),技多不压身。
附上我的面试各大专题整理: 面试指南,满满的都是干货,希望对大家有帮助!
[外链图片转存中…(img-AusvBzHL-1711536216211)]