每种手机都有自己的休眠策略,
Android
手机在长时间不操作时会自动让CPU进入睡眠状态,这就导致JAVA原生Timer
的定时任务无法运行。
所以我们需要借助
Alarm
唤醒CPU
一、Alarm
机制
Alarm借助了
AlermManager
类,这个类和NotificationManger
类似。通过调用Context
的getSystemService()
,来获取实例,不过这里要传入Context..ALARM_SERVICE
,因此,获取AlarmManager
实例可以写成:
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
接下来调用
AlertManager
的set()
方法就能设置一个定时任务,比如10秒后任务执行:
long triggerAtTime = SystemClock.elapsedRealtime() + 10*1000;
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);
SystemClock.elepsedRealtime()
可以获取到系统开机至今的毫秒数System.cuurrentTimeMillis()
可以获取到1970.1.1至今的毫秒数set()
方法有三个参数:
第一个参数:整型参数,用于指定工作类型,有四种值可选:
ELAPSED_REALTIME
:定时任务的触发时间从开机开始算起,但不会唤醒CPU
ELAPSED_REALTIME_WAKEUP
:定时任务的触发时间从系统开机开始算起,会唤醒CPU
RTC
:定时任务的触发时间从1970.1.1开始算起,但不会唤醒CPU
RTC_WAKEUP
:定时任务的触发事件从1970.1.1开始算起,但会唤醒CPU
第二个参数:任务的触发时间,以毫秒为单位
第三个参数PendingIntent
,一个可以触发的广播或服务
再比如要实现一个可以长时间在后台定时运行的服务:
首先建一个普通的服务,比如起名为
LongRunningService
,然后把触发定时任务的代码写在onStartCommand()
:
public class LongRunningService extends Service{
@Override
public IBinder onBind(Intent intent){
return null;
}
@Overide
public int onStartCommand(Intent intent, int flags, int startId){
new Thread(new Runnable(){
@Override
public void run(){
// 在这里执行具体的逻辑事件
}
}).start();
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int anHour = 60*60*1000;
long triggerAtTime = SystemClock.elapsedRealtime()+anHour();
Intent i = new Intent(this, LongRunningService.class);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
return super.onStartCommand(intent, flags, startId);
}
}
这样就能保证定时任务每一小时执行依次一次,最后,这样启动这个定时任务:
Intent intent = new Intent(context, LongRunningService.class);
context.startService(intent);
Androiod4.4 之后,Alarm任务的触发时间不再准确,这是系统做出了耗电优化,用
setExact()
代替set()
即可准时运行
二、Doze
模式
在安卓6.0之后,谷歌又加入了全新的Doze模式,就是说当屏幕关闭一段时间后,系统会对CPU,网络、Alarm等活动做出限制,从而延长电池寿命
但是系统会间歇性退出
Doze
模式一小段时间,让应用完成他们的同步操作和Alerm任务。
具体限制:
网络访问被禁止 忽略唤醒CPU和屏幕操作 不再wifi扫描 不再执行同步任务 Alarm任务将会在下次退出Doze模式时执行这使得我们的Alarm任务不再准时,但如果你非要准时执行,也有特殊方案:
AlarmManager.setAndAllowWhileIdle()
或 AlermManager,setExactAndAllowWhileIdle()
使得Doze模式也能正常执行定时任务,使用方法和之前的setExact()
或set()
一样
作者:有意识的呼吸