程序性能优化之耗电优化(四)下篇

如果要模拟的不是耗时任务,那就去掉这个Handler,然后将onStartJob的返回值设置为false。因为在onStartJob里返回false代表你任务执行完成了,他会开始计时为下一次任务的执行做准备,如果返回true,代表任务还在执行,需要我们自己调用jobFinished(param,true)函数来告诉JobService任务执行完成了

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)//API需要在21及以上
public class MyJobService extends JobService {

private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Toast.makeText(MyJobService.this, “MyJobService”, Toast.LENGTH_SHORT).show();
JobParameters param = (JobParameters) msg.obj;
jobFinished(param, true);

return true;
}
});

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}

@Override
public boolean onStartJob(JobParameters params) {
Message m = Message.obtain();
m.obj = params;
handler.sendMessageDelayed(m, 2000);
return true;
}

@Override
public boolean onStopJob(JobParameters params) {
handler.removeCallbacksAndMessages(null);
return false;
}
}

因为是Service还需要在AndroidManifest注册,只是注册时还需要设置一个特殊的权限

activity就是设置一个按钮,点击触发任务的调度开启

public class MainActivity extends AppCompatActivity {

Button btn;
private JobScheduler mJobScheduler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btn = (Button) findViewById(R.id.btn);
mJobScheduler = (JobScheduler) getSystemService( Context.JOB_SCHEDULER_SERVICE );
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
JobInfo.Builder builder = new JobInfo.Builder( 1,
new ComponentName( getPackageName(), MyJobService.class.getName() ) );
builder.setMinimumLatency(2000);
if( mJobScheduler.schedule( builder.build() ) <= 0 ) {
//If something goes wrong
}
}
}
});
}
}

(2)各种使用情况
setMinimumLatency
基础代码里通过setMinimumLatency(2000)设置任务最少执行延缓,虽然是最少延缓,但是在我的测试下,发现这个延缓时间比较随机,有时候能够在两秒后开始执行任务,不过一般的都是7、8秒开始执行任务。在任务执行完成后,他们会初始化延缓时间,开始计时,准备下一次任务的执行。

setPeriodic
在基础代码里,我把setMinimumLatency(2000)代码换成setPeriodic(2000)

这里要注意setMinimumLatency和setPeriodic不能一起设置,会报错,我想是因为他们都有周期设置任务启动的特性有关。

当我运行代码,应用却没有按照两秒周期的时间触发任务,然后我在控制台看到了如下log

W/JobInfo: Specified interval for 1 is +2s0ms. Clamped to +15m0s0ms
W/JobInfo: Specified flex for 1 is +2s0ms. Clamped to +5m0s0ms

就是说你这个间隔必须在15分钟以上,这个规定是在Android7.0开始有的,所以如果需要比较频繁的调用任务,还是需要使用setMinimumLatency来完成。
setRequireNetworkType
如果我把setRequireNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)替换setMinimumLatency(2000),运行程序会报错

java.lang.IllegalArgumentException: You’re trying to build a job with no constraints, this is not allowed.

我得出结论setRequireNetworkType不算主约束条件,需要依附像setMinimumLatency类似的主约束条件,那好我添加一个setMinimumLatency(2000000),再来运行,之所以把最少延缓的时间设置的这么大,是因为只要满足设置的条件之一就会启动任务。
然后运行程序,当我们连接WIFI,就会触发任务,市面很多通知栏广告就是使用这个类型的网络类型触发的,因为JobInfo规定的网络类型还有几个,我就不试了,大家可以自己试试

public static final int NETWORK_TYPE_ANY = 1;
public static final int NETWORK_TYPE_METERED = 4;
public static final int NETWORK_TYPE_NONE = 0;
public static final int NETWORK_TYPE_NOT_ROAMING = 3;
public static final int NETWORK_TYPE_UNMETERED = 2;

setRequiresChargin
setRequiresChargin不是主约束条件, 将setRequiresChargin(true)替换setRequireNetworkType(JobInfo.NETWORK_TYPE_UNMETERED),运行程序。
setRequiresChargin(true)指的是监听充电,如果给的false就不监听,所以默认就是false

setOverrideDeadline
如果jobInfo配置如下

JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()))
.setPeriodic(2000)
.setOverrideDeadline(10000)
.build();

运行程序会报错

java.lang.IllegalArgumentException: Can’t call setOverrideDeadline() on a periodic job.
如果我去掉setPeriodic(2000)这行代码,在运行程序,我发现点击一次按钮就会立即启动任务,也就是弹出Toast,但是后面会继续启动任务,只是间隔时间比10秒时间要长得多

现在JobInfo代码我写成如下

JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()))
.setOverrideDeadline(5000)
.setMinimumLatency(3000)
.build();

程序运行正常,符合预期
setPersisted
setPersisted不是一个主约束条件,当JobInfo代码如下

JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()))
//.setMinimumLatency(10000)
.setPersisted(true)
.build();

按下按钮,然后重启手机,没有效果。。。。。

setRequiresDeviceIdle
代码如下

JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()))
.setRequiresDeviceIdle(true)
.build();

额,手机空闲状态,明明其他手机程序都退出来,半天等不到,

(3)JobSheduler任务调度
之前我们在基础代码里看到了以下代码,就是判断任务是否创建成功,但是这还不是任务调度的范围

if( mJobScheduler.schedule( builder.build() ) <= 0 ) {
//If something goes wrong
}

首先我们看看cancel函数的效果,activity的代码里加一个button,为了触发cancel函数

public class MainActivity extends AppCompatActivity {

Button btn, btn_pause;
private JobScheduler mJobScheduler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btn = (Button) findViewById(R.id.btn);
btn_pause = (Button) findViewById(R.id.btn_pause) ;
mJobScheduler = (JobScheduler) getSystemService( Context.JOB_SCHEDULER_SERVICE );
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
JobInfo.Builder builder = new JobInfo.Builder( 1,
new ComponentName( getPackageName(), MyJobService.class.getName() ) );
builder.setMinimumLatency(20000);
if( mJobScheduler.schedule( builder.build() ) <= 0 ) {
//If something goes wrong
}
}
}
});
btn_pause.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mJobScheduler.cancel(1);
}
}
});

}

}

运行程序,点击第一个按钮,然后再点击第二个按钮,确认任务没有被启动过,把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 优点:

  1. 可以由容器来管理线程
  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 项的当前状态。
注意:

尾声

你不踏出去一步,永远不知道自己潜力有多大,千万别被这个社会套在我们身上的枷锁给捆住了,30岁我不怕,35岁我一样不怕,去做自己想做的事,为自己拼一把吧!不试试怎么知道你不行呢?

改变人生,没有什么捷径可言,这条路需要自己亲自去走一走,只有深入思考,不断反思总结,保持学习的热情,一步一步构建自己完整的知识体系,才是最终的制胜之道,也是程序员应该承担的使命。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)**

[外链图片转存中…(img-s6utDUZt-1715351995616)]

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 16
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值