官方解释:AlarmManager类提供对系统警报服务的访问。这些允许您安排应用程序在将来的某个时间运行。当警报响起时,Intent
系统会广播为其注册的警报,如果目标应用程序尚未运行,则会自动启动它。设备处于休眠状态时会保留已注册的警报(如果设备在此期间关闭,则可以选择将设备唤醒),但如果设备关闭并重新启动,则会清除AlarmManager的任务。
通俗一点:AlarmManager 系统提供的一个定时任务管理器,通过AlarmManager 提供的定时任务,可以在约定的时间发送广播,启动服务,启动Activity等等。AlarmManager是Android中常用的一种系统级别的提示服务,在特定的时刻为我们广播⼀个指定的Intent。简单的说就是我们设定⼀一个时间,然后在该时间到来时,AlarmManager为 我们广播一个我们设定的Intent广播因此我们需要实现⼀一个针对特定闹钟事件的⼴播接⼝器 (PendingIntent)。
特点:使用它既可以指定单次执行的定时任务,也可以指定重复运行的周期性任务;
注意:从API 19开始,AlarmManager的机制都是非准确传递,操作系统将会转换闹钟,来最小化唤醒和电池使用,所以时间可能没那么精确;AlarmManager非常适合Android中定时任务.并且因为他具有唤醒CPU的功能,可以保证每次需要执行特定任务时CPU都能正常工作, 或者说当CPU处于休眠时注册的闹钟会被保留(可以唤醒CPU),(老司机们请注意此处有弯道减速慢行)但是国内Rom众多.有的可能休眠时候无法唤醒。
简单的使用流程
eg1:
int time = 60 * 1000 * 30;//30分钟
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, RepetitionService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT < 19) {
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + time, pendingIntent);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + time, pendingIntent);
}
这里time 表示30分钟后, 会启动intent对象设置的RepetitionService
下面看下RepetitionService 代码:
public class RepetitionService extends IntentService {
public static final String TAG = "RepetitionService";
public RepetitionService() {
super("RepetitionService");
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
}
@Override
protected void onHandleIntent(Intent intent) {
做一些逻辑,由于IntentService 会进行异步处理,
所以这里可以直接写耗时逻辑,不会占用主线程耗时,不需要再开启异步线程,
onHandleIntent 执行完后, Service会自动销毁;
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
}
当然这里启动的是一个Service ,可以换为通过Intent发送一自定义Action的广播,用法类似;
通常要使用 PendingIntent,PendingIntent可以理解为Intent的封装包,简单的说就是在Intent上在加个指定的动作。在使用Intent的时候,我们还需要在执行startActivity、startService或sendBroadcast才能使Intent有用。而PendingIntent的话就是将这个动作包含在内了。
eg2: 设定指定时间后执行任务(用Calendar来定义时间)
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR,2016);
calendar.set(Calendar.MONTH,Calendar.DECEMBER);
calendar.set(Calendar.DAY_OF_MONTH,16);
calendar.set(Calendar.HOUR_OF_DAY,11);
calendar.set(Calendar.MINUTE,50);
calendar.set(Calendar.SECOND,0);
//设定时间为 2016年12月16日11点50分0秒
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmService.class);
intent.setAction(AlarmService.ACTION_ALARM);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if(Build.VERSION.SDK_INT < 19){
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}else{
am.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
public class AlarmService extends Service {
public static String ACTION_ALARM = "action_alarm";
private Handler mHanler = new Handler(Looper.getMainLooper());
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mHanler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(AlarmService.this, "闹钟来啦", Toast.LENGTH_SHORT).show();
}
});
return super.onStartCommand(intent, flags, startId);
}
}
AlarmManager的几个方法:
设置一次性闹钟:
set(int type, long triggerAtMillis, PendingIntent operation)
第一个参数表示闹钟类型
第二个参数表示闹钟执行时间
第三个参数表示闹钟响应动作
设置重复闹钟: SDK_19 Android4.4 之前是精确闹钟,19以后为了节约电量,减少系统唤醒和电池的使用,所以时间没有那么精确了,但是不会差太多
setRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)
setInexactRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)
第一个参数表示闹钟类型,
第二个参数表示闹钟首次执行时间,
第三个参数表示闹钟两次执行的间隔时间,
第四个参数表示闹钟响应动作
设置精确闹钟:
setExact(int type, long triggerAtMillis, PendingIntent operation)
setWindow(int type, long windowStartMillis, long windowLengthMillis,PendingIntent operation)
取消闹钟:
cancel(PendingIntent operation)
取消Intent相同的闹钟,这里是根据Intent中filterEquals(Intent other)方法来判断是否相同,
public boolean filterEquals(Intent other) {
if (other == null) {
return false;
}
if (!Objects.equals(this.mAction, other.mAction)) return false;
if (!Objects.equals(this.mData, other.mData)) return false;
if (!Objects.equals(this.mType, other.mType)) return false;
if (!Objects.equals(this.mPackage, other.mPackage)) return false;
if (!Objects.equals(this.mComponent, other.mComponent)) return false;
if (!Objects.equals(this.mCategories, other.mCategories)) return false;
return true;
}
可以看到,从方法体可以看出mAction、mData、mType、mPackage、mComponent、mCategories这几个完全一样就认定为同一Intent ,才能取消, 否则认为不是同一个Intent ,就不能取消,时间到了之后还是会执行;
闹钟类型
闹钟重复类型
设定多个定时闹钟为什么只有最后一个生效
AlarmManager 根据 PendingIntent requestCode 来判断是否是同一个定时服务,所以当requestCode相等的时候只有最后一个生效
1. 我们说的requestCode 是第二个参数
PendingIntent.getBroadcast(Context context, int requestCode, Intent intent, @Flags int flags)
2. 例如:
PendingIntent pi1 = PendingIntent.getBroadcast(this, 1, intent, 0);
AlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalTime, pi1);
PendingIntent pi2 = PendingIntent.getBroadcast(this, 2, intent, 0);
AlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalTime, pi2);
这个样子就可以设定2个了