1.Service

引入版本:所有

简介:

8.0之前作为一个稳定的安卓组件而使用。

安卓8.0版本开始引入了限制,startService在熄屏一段时间后执行会抛出 异常,Service在熄屏一段时间会被停止,好消息是bindService暂时还可用,不过感觉谷歌也是早晚把这个口堵上。

 

2.AlarmManager

引入版本:所有

简介:

在安卓4.4之前,set可以精准定时;

4.4之后,set 方法和 setRepeating 方法存在一些问题,无法实现准确定时,可能会有些延迟,官方也提供了准确定时的替代方法,即 setExact 和 setWindow,但是这两个方法都只是执行一次性操作的;

6.0之后,setExact无法在doze状态执行,需要使用setExactAndAllowWhileIdle。

 

复制一段项目中的kotlin代码(如果使用系统时间而不是RTC时间,需要替换RTC_WAKEUP标记):

private fun schedulePendingIntent(ctx: Context, pendingIntent: PendingIntent, delayMs: Long) {

    val nextAlarmInMilliseconds = System.currentTimeMillis() + delayMs

    val alarmManager = ctx.getSystemService(Service.ALARM_SERVICE) as AlarmManager

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

        // In SDK 23 and above, dosing will prevent setExact, setExactAndAllowWhileIdle will force

        // the device to run this task whilst dosing.

        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextAlarmInMilliseconds,

        pendingIntent)

    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

        alarmManager.setExact(AlarmManager.RTC_WAKEUP, nextAlarmInMilliseconds,

        pendingIntent)

    } else {

        alarmManager.set(AlarmManager.RTC_WAKEUP, nextAlarmInMilliseconds,

        pendingIntent)

    }

}

 

在安卓6.0之后,引入doze。为了支持doze模式,增加了新API:setExactAndAllowWhileIdle,这个方法可以在doze进入idle后执行。平时有最小执行间隔,印象是10s?(定时1s后,也是10s后执行)。在进入doze后,最小执行间隔是9min。

 

如何进入doze idle状态呢?引入安卓7.0(看的是7.0而不是6.0的代码)的doze时序图:

android自动息屏时间在哪里设置_静态注册

坑1:测了一个4.4的魅族手机,AlarmManager无法准时运行,和APP的系统设置有关

坑2:华为8.0activity处于stop状态会推迟AlarmManager

结论:

AlaramManager虽然各版本有差异,但还是比较稳定的API

 

3.JobScheduler

引入版本:5.0

简介:

和BroadReceiver一样,在执行期间不需要申请WakeLock,onStartJob的返回值决定手动释放WakeLock或是手动。

作为谷歌力推的后台工作组件,JobScheduler有代替AlarmManager的趋势。和AlarmManager相比,JobScheduler状态更多,也可以实现如监控后台网络变化等工作。

JobScheduler在原生rom中,即使app被杀死,也可以被唤醒并被继续执行,猜测这应该要归功于JobService。

 

坑1:在国内很多厂ROM中,清理后台后JobScheduler任务会被清理,想唤醒还是别做梦了

坑2:在MIUI9.2(安卓7.0)系统中,实测JobScheduler在停止充电并熄屏几分钟后停止执行,而同一台机改用AlarmManager程序则活蹦乱跳的

坑3:华为8.0activity处于stop状态会推迟JobScheduler

 

结论:

想拉活,别做梦,老老实实用手机厂商的推送。

想准确,国内有点难,目前就测了一个MIUI就不行,想要通用,用回AlarmManager?牺牲准度换取通用性?

 

4.JobIntentService

引入版本:所有

这货是在support包中的,所有版本可用,为了替代IntentService,安卓8.0有时无法startService了,这下用JobIntentService的API完美替代吧

 

5.BroadReceiver

引入版本:所有

再熟悉不过了。

onReceive方法执行时短暂持有WakeLock,不能执行耗时操作。

在原生安卓系统,静态注册的接收器可以监听一些广播拉活APP。

在高版本中谷歌逐渐去除一些隐式广播以及静态注册的支持,动态注册依然可用。

坑1:想要监听网络状态变化,在高版本只能在前台监听,后台需要用JobScheduler等方式。

 

android8.0规避startService无法调用的技巧:

国人的智慧是无穷的,android8.0在后台过久后startService调用抛出异常,个推是怎么解决的呢?

启动一个空Activity,在Activity#onCreate中startService,为个推团队的机智点赞。

 

实验:

安卓模拟器原生8.0,插电debug,UI退到后台,startService后过一段时间服务就会被stop,测试时只用了1分17秒,在onDestroy中直接发送广播通知广播接收器bindService,服务则不会被杀

红米note4,android7.0,过一段时间service也被stop过,未仔细测试

小米8,android8.0,程序退到后台,启动服务很久未见服务停止,电源已拔

结论:虽然8.0会停止未绑定的Service,但国内ROM并不都会停止Service,同一家不同版本行为都不一样,保险点都监听下服务停止就好了