Android 6.0+ (api 23+)应用保活方案研究

Android 6.0开始,系统引进了一个Doze系统的概念。Doze系统是只当设备被闲置,用户没有对设备有互动的操作,也就是锁屏的情况下,系统过一段时间进入这个Doze模式,其中还有一个定义叫idle模式的在doze的中间,我叫它是深入睡眠。在idle模式下,系统可以关闭一些后台程序,包括常驻的service(就算你是sticky也无力抵抗),网络更新,同步,闹钟,减少它们的活动频率,从而达到省电的目的。虽然有了这个东西,电是省了,但是对于一些实时性要求比较高的app就出了道难题。下面我来说说两个方案。

JobScheduler工作调度器
Android 5.0开始引进的一个单例模式的任务调度服务,它可以在idle模式下也可以执行,设备重启后依然有效。JobScheduler在执行任务时会自动唤起cpu的WakeLock,从而达到保活效果。JobScheduler的任务执行完全由系统来支配,包括在idle模式下也如此,我们只需要在任务执行所回调给JobService的onStartJob方法中做实际要保活的内容。当然,系统有权终止这些任务,系统终止了任务回调onStopJob。
下面是获取到JobScheduler服务,然后加入JobInfo工作任务。
JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobBuilder.build());
下面再看创建JobInfo工作任务。
//需要一个int类型作为jobInfo的id,这标记以便可以取消这个任务。
int jobId = 1;
//任务回调道MyJobService,继承JobService
ComponentName componentName = new ComponentName(this,MyJobService.class);
        JobInfo.Builder jobBuilder = new JobInfo.Builder(jobId,componentName);
// 设置重复周期为5秒一次
jobBuilder.setPeriodic(TimeUnit.SECONDS.toMillis(5L));
//设置为重复的任务
jobBuilder.setPersisted(true);
//设置为在idle模式下有效
jobBuilder.setRequiresDeviceIdle(true);
//可以给回调的任务传递参数
PersistableBundle bundle = new PersistableBundle();
bundle.putString("tag","hello");
jobBuilder.setExtras(bundle);
在mainifest中给MyJobServcie权限
<service android:name=".MyJobService"
    android:exported="true"
    android:permission="android.permission.BIND_JOB_SERVICE"/>
要做这个重复任务,还要加入权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
来看看我执行的结果


【总结】
优点:实时性强,精确到5秒。
缺点:准确率不高,进入idle模式下,无法控制任务触发时间,调度时间间隔越来越长。有部分国产机不支持,像小米就不支持它的重复任务。

AlarmManager
它是老东西,而且前面已经提到了Doze也会把它终止,那为什么它还会出现呢?当然,Android 6.0为它引进了一个新的api,专门克制Doze。那就是setExactAndAllowWhileIdle(),能够使idle模式下的cpu苏醒过来。
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
        long time = 2000;
        PendingIntent pending = PendingIntent.getBroadcast(MainActivity.this,1
                ,new Intent("com.arjinmc.test"),PendingIntent.FLAG_UPDATE_CURRENT);
        if (Build.VERSION.SDK_INT >= 23) {
            am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time,
                    pending);
        } else if (Build.VERSION.SDK_INT >= 19) {
            am.setExact(AlarmManager.RTC_WAKEUP, time, pending);
        } else {
            am.set(AlarmManager.RTC_WAKEUP, time, pending);
        }
        am.setRepeating(AlarmManager.RTC_WAKEUP,1000l,1000l,pending);
我这里用闹钟回调的是broadcast,你也可以改成service。broadcast和service的启动执行都跟一般的用法一样,这里我就不贴代码了。当然要在实现任务的时候把要把cpu的WakeLock唤起。

再来看看我的运行效果。


【总结】
优点:准确率高,在idle模式下依然能保持比较准确的时间内唤醒cpu。
缺点:精准度相对比较低,只能精确到1分钟。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值