阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680
本篇文章将最后从以下两个方面来介绍耗电优化:
- 【JobScheduler】
- 【WorkManager】
一、JobScheduler API的使用详细
1.1 简介
JobScheduler API是在Android5.0开始有的,使用场景:在稍后的某个时间点或者当满足某个特定的条件(连接电源,网络状态变化、手机是否空闲)时需要执行一个任务。
1.2 API函数
开发者主要通过三个类JobService和JobScheduler、JobInfo来使用JobSchedule API
而且你要知道一件事,一旦通过命令开启了任务,只要符合条件就会执行任务,除非应用程序死亡,所以比如设置周期运行任务的,会不断的启动任务
JobScheduler实现了任务的调度,相关函数如下
JobService是一个抽象类,是Service的继承类,我们需要实现两个个函数,来完成任务执行的开始和停止
JobInfo是为了规定任务启动的规则,通过JobScheduler的建造者模式来设置规则
1.3 各种使用
(1)基础代码
首先我贴出一个最基本JobSheduler API的使用代码,后面的测试代码都是通过这个段代码稍微改动而来的,大家可以边看博客,自己试一试代码的效果
MyJobService就是显示一个Toast,之所以最后是通过Handler实现,是因为想要模仿耗时任务,毕竟这是一个后台Service,使用场景很多是耗时任务。
如果要模拟的不是耗时任务,那就去掉这个Handler,然后将onStartJob的返回值设置为false。因为在onStartJob里返回false代表你任务执行完成了,他会开始计时为下一次任务的执行做准备,如果返回true,代表任务还在执行,需要我们自己调用jobFinished(param,true)函数来告诉JobService任务执行完成了
因为是Service还需要在AndroidManifest注册,只是注册时还需要设置一个特殊的权限
activity就是设置一个按钮,点击触发任务的调度开启
(2)各种使用情况
setMinimumLatency
基础代码里通过setMinimumLatency(2000)设置任务最少执行延缓,虽然是最少延缓,但是在我的测试下,发现这个延缓时间比较随机,有时候能够在两秒后开始执行任务,不过一般的都是7、8秒开始执行任务。在任务执行完成后,他们会初始化延缓时间,开始计时,准备下一次任务的执行。
setPeriodic
在基础代码里,我把setMinimumLatency(2000)代码换成setPeriodic(2000)
这里要注意setMinimumLatency和setPeriodic不能一起设置,会报错,我想是因为他们都有周期设置任务启动的特性有关。
当我运行代码,应用却没有按照两秒周期的时间触发任务,然后我在控制台看到了如下log
就是说你这个间隔必须在15分钟以上,这个规定是在Android7.0开始有的,所以如果需要比较频繁的调用任务,还是需要使用setMinimumLatency来完成。
setRequireNetworkType
如果我把setRequireNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)替换setMinimumLatency(2000),运行程序会报错
我得出结论setRequireNetworkType不算主约束条件,需要依附像setMinimumLatency类似的主约束条件,那好我添加一个setMinimumLatency(2000000),再来运行,之所以把最少延缓的时间设置的这么大,是因为只要满足设置的条件之一就会启动任务。
然后运行程序,当我们连接WIFI,就会触发任务,市面很多通知栏广告就是使用这个类型的网络类型触发的,因为JobInfo规定的网络类型还有几个,我就不试了,大家可以自己试试
setRequiresChargin
setRequiresChargin不是主约束条件, 将setRequiresChargin(true)替换setRequireNetworkType(JobInfo.NETWORK_TYPE_UNMETERED),运行程序。
setRequiresChargin(true)指的是监听充电,如果给的false就不监听,所以默认就是false
setOverrideDeadline
如果jobInfo配置如下
运行程序会报错
现在JobInfo代码我写成如下
程序运行正常,符合预期
setPersisted
setPersisted不是一个主约束条件,当JobInfo代码如下
按下按钮,然后重启手机,没有效果。。。。。
setRequiresDeviceIdle
代码如下
额,手机空闲状态,明明其他手机程序都退出来,半天等不到,
(3)JobSheduler任务调度
之前我们在基础代码里看到了以下代码,就是判断任务是否创建成功,但是这还不是任务调度的范围
首先我们看看cancel函数的效果,activity的代码里加一个button,为了触发cancel函数
运行程序,点击第一个按钮,然后再点击第二个按钮,确认任务没有被启动过,把cancel函数缓存cancelAll效果一样。
其实还有函数可以看到未执行任务的函数,比如getPendingJob,但是这一个需要手机系统是Android7.0以上的。
二、WorkManager 的使用及优势
commonj.work.WorkManager
2.1 描述:
工作管理器 (commonj.work) API 提供的接口允许应用程序在一个容器中并发地执行多个工作项。
实际上,此 API 就是 java.lang.Thread API 的容器管理替代方法。但是java.lang.Thread API 不适用于受管 Java EE 环境中承载的应用程序。在这样的环境中,WorkManager的效果更好,因为它允许容器全面查看和控制所有执行线程。
注意:
工作管理器 API 不提供故障转移和持久性机制。如果受管服务器环境出现故障或关闭,则当前所有工作都将丢失。
2.2 优点:
- 可以由容器来管理线程
- 可以协调多个线程共同工作
接口:
WorkManager - 此接口提供一组用于调度要执行工作的调度方法。
系统管理员可在服务器级别定义 WorkManager。WorkManager 实例通过执行 JNDI 查找来获取。受管的环境可以支持多个 WorkManager 实例。请参阅"WebLogic JNDI 编程"。您在部署期间将 WorkManager 配置为 resource-ref。。
Work - 通过此接口,您可以异步运行应用程序代码。通过创建实现此接口的类,您可以创建可通过调度在特定的时间或定义的间隔运行的代码块。换句话说,此为在工作管理器 API 中处理的"工作"。
WorkItem - 在将 Work 实例提交给 WorkManager 后,WorkManager 将返回一个 WorkItem。此 WorkItem 用于确定整个 Work 实例的状态。
WorkListener - WorkListener 接口是一个回调接口,它在 WorkManager 与 Work 实例中定义的调度工作之间建立通信。
WorkItem item = WorkManager.schedule(Work work, WorkListener wl);
可以使用 WorkListener 确定 Work 项的当前状态。
注意:
WorkListener 实例总与通过 WorkManager 调度 Work 的初始线程在同一个 JVM 中执行。
web.xml:
<resource-ref>
<res-ref-name>wm/ThreadsWorkManager</res-ref-name>
<res-type>commonj.work.WorkManager</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
**Java code: **
可以在Listener 或 servlet中用以下代码来获取WorkManager。
WorkManager wm =(WorkManager)ic.lookup("java:comp/env/wm/ThreadsWorkManager");
wm.schedule(new OpenWOWork());
Work Manager具有两个无可比拟的优势:
-
使多个Work之间协作起来,例如使用监听器,当一个任务完成后再开始另一个任务。
-
线程由服务器统一管理起来,如果服务器的将该应用停掉,就会shut down 所有的work,当然你也可以选择不shut down. 但是它提供了这个的功能让用户在使用时可以保证不会因为多次部署而导致应用产生多个线程在跑。
参考:https://www.iteye.com/blog/dana-wang-2160023
https://blog.csdn.net/z979451341/article/details/80608607
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680