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时序图:
坑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,同一家不同版本行为都不一样,保险点都监听下服务停止就好了