介绍
AlarmManager是Android中常用的一种系统级别的提示服务,在特定的时刻为我们广播一个指定的Intent。简单的说就是我们设定一个时间,然后在该时间到来时,AlarmManager为我们广播一个我们设定的Intent,通常我们使用 PendingIntent,PendingIntent可以理解为Intent的封装包,简单的说就是在Intent上在加个指定的动作。在使用Intent的时候,我们还需要在执行startActivity、startService或sendBroadcast才能使Intent有用。而PendingIntent的话就是将这个动作包含在内了。
注意!因为在较高的android版本(大概应该是5.0,其他厂商的机器都会有所不同)里,为了节省电源使用了一种在一段时间的所有定时器都会自动合并到一个时间点上一起发出的机制。所以,现在的定时器启动的时间并不是十分精确,它只是一个大概时间。就算你在后续设置了精确版本重复模式也是如此,它只是稍微好一点点。
创建流程
- 创建Intent用来告诉定时器触发后它要做什么,Intent可以是启动activity、启动Service、发送广播。
- 创建时间值用来告诉定时器什么时候触发。
- 创建PendingIntent(等待Intent)用来包裹创建好的Intent。
- 取得AlarmManager系统服务,强制转型并且实例化
- 用AlarmManager实例以set方法,添加类型、时间值、PendingIntent参数
简单Demo了解流程
关于更详解的了解在后续说明,我们先简单大概的了解一下使用流程。帮助理解后续更详细的参数说明。
我们创建一个定时器启动Activity的简单demo:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time);
mBtnStart = (Button)findViewById(R.id.btn_start);
mBtnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//正常的创建intent,TimeDemoActivity是我要启动的活动
Intent intent = new Intent(TimeActivity.this,TimeDemoActivity.class);
long time = System.currentTimeMillis()+5*1000;//得到当前时间并且增加5秒,表示我们在5秒后触发定时器
//创建PendingIntent封装了intent
PendingIntent pi = PendingIntent.getActivity(TimeActivity.this,0,intent,0);
AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);//得到系统AlarmManager服务
//设置了AlarmManager类型参数,时间值,PendingIntent
manager.set(AlarmManager.RTC_WAKEUP,time,pi);
}
});
}
这样就完成了,下面我们来看看效果:
PendingIntent对象
//这是启动activity的PendingIntent
PendingIntent pi = PendingIntent.getActivity(TimeActivity.this,0,intent,0);
- 启动Activity: PendingIntent对象的获取就应该采用 PendingIntent.getActivity(Context c,int i,Intent intent,int j)方法。
- 启动服务: PendingIntent对象的获取就应该采用Pending.getService(Context c,int i,Intent intent,int j)方法;
- 广播: PendingIntent对象的获取就应该采用 PendingIntent.getBroadcast(Context c,int i,Intent intent,int j)方法;
AlarmManager详解
常用set方法
- set(int type,long startTime,PendingIntent pi);该方法用于设置一次性闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟执行时间,第三个参数表示闹钟响应动作。
- setRepeating(int type,long startTime,long intervalTime,PendingIntent pi);该方法用于设置重复闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟首次执行时间,第三个参数表示闹钟两次执行的间隔时间,第三个参数表示闹钟响应动作。
- setInexactRepeating(int type,long startTime,long intervalTime,PendingIntent pi);该方法也用于设置重复闹钟,重复闹钟的不精确版本,它相对而言更节能(power-efficient)一些,因为系统可能会将几个差不多的闹钟合并为一个来执行,减少设备的唤醒次数。
- setTimeZone(String timeZone) ;设置系统的默认时区。需要android.permission.SET_TIME_ZONE权限
set方法各参数详解
不介绍setTimeZone方法
int type 参数
闹钟的类型,常用的有5个值:AlarmManager.ELAPSED_REALTIME、 AlarmManager.ELAPSED_REALTIME_WAKEUP、AlarmManager.RTC、 AlarmManager.RTC_WAKEUP、AlarmManager.POWER_OFF_WAKEUP。
- AlarmManager.ELAPSED_REALTIME表示闹钟在手机睡眠状态下不可用,该状态下闹钟使用相对时间(相对于系统启动开始),状态值为3;
- AlarmManager.ELAPSED_REALTIME_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟也使用相对时间,状态值为2;
- AlarmManager.RTC表示闹钟在睡眠状态下不可用,该状态下闹钟使用绝对时间,即当前系统时间,状态值为1;
- AlarmManager.RTC_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟使用绝对时间,状态值为0;
- AlarmManager.POWER_OFF_WAKEUP表示闹钟在手机关机状态下也能正常进行提示功能,所以是5个状态中用的最多的状态之一,该状态下闹钟也是用绝对时间,状态值为4;不过本状态好像受SDK版本影响,某些版本并不支持;
long startTime 参数
闹钟的第一次执行时间,以毫秒为单位,可以自定义时间,不过一般使用当前时间。需要注意的是,本属性与第一个属性(type)密切相关,如果第一个参数对 应的闹钟使用的是相对时间(ELAPSED_REALTIME和ELAPSED_REALTIME_WAKEUP),那么本属性就得使用相对时间(相对于 系统启动时间来说),比如当前时间就表示为:SystemClock.elapsedRealtime();如果第一个参数对应的闹钟使用的是绝对时间 (RTC、RTC_WAKEUP、POWER_OFF_WAKEUP),那么本属性就得使用绝对时间,比如当前时间就表示 为:System.currentTimeMillis()。
long intervalTime 参数
对于后两个方法来说,存在本属性,表示两次闹钟执行的间隔时间,也是以毫秒为单位。这里系统代码上已经提供了一些快捷的间隔时间,让你可以不需要在另外计算一天的毫秒级时间:
- INTERVAL_DAY = 86400000L;//设置闹钟,间隔一天
- INTERVAL_FIFTEEN_MINUTES = 900000L; //设置闹钟,间隔15分钟
- INTERVAL_HALF_DAY = 43200000L; //设置闹钟,间隔半天
- INTERVAL_HALF_HOUR = 1800000L; //设置闹钟,间隔半个小时
- INTERVAL_HOUR = 3600000L; //设置闹钟,间隔一个小时
使用方法:
manager.setRepeating(AlarmManager.RTC_WAKEUP,time+10*1000,AlarmManager.INTERVAL_DAY,pi);
PendingIntent pi 参数
绑定了闹钟的执行动作,比如发送一个广播、给出提示等等。PendingIntent是Intent的封装类。
取消已经注册的AlarmManager
AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent intent = new Intent(AlarmTest.this, AlarmActivity.class);
intent.setAction("111111");
PendingIntent pendingIntent = PendingIntent.getActivity( AlarmTest.this, 0, intent, 0);
manager.cancel(pendingIntent);
说明一下为什么需要setAction,因为有一种情况就是多个 AlarmManager 都在不同时间段要启动相同activity的intent,所以为了区分不同时段的intent,我们需要添加setAction。这样取消的时候只会取消指定的intent。注意!如果你添加了2个一样的Intent到定时器里,那么第一个被添加到定时器的Intent会自动被取消。
了解时间值的创建
请移步到本人另一篇博客了解Java的时间值操作与获取:https://blog.csdn.net/qq_37217804/article/details/81741684取消
Demo演示
定时器广播Demo_1
注意!必需静态广播!
在AndroidManifest.xml静态广播注册与action接收器注册:
<receiver
android:name=".ui.MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.xxx.xxx.MyReceiver"/>
</intent-filter>
</receiver>
创建接收器class:
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.yt.owl.MyReceiver")) {
Toast.makeText(context, "定时器广播成功接收", Toast.LENGTH_SHORT).show();
}
}
}
创建定时器:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time);
mBtnStart = (Button)findViewById(R.id.btn_start);
mBtnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mFormat = new SimpleDateFormat("yyyy年MM月dd日 : HH时mm分ss秒");
long time = System.currentTimeMillis();
Log.e(TAG, "TIME1: "+time);
Intent intent = new Intent(TimeActivity.this,MyReceiver.class);
intent.setAction("com.xxx.xxx.MyReceiver");
PendingIntent pt = PendingIntent.getBroadcast(TimeActivity.this,0,intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);
manager.set(AlarmManager.RTC_WAKEUP,time+5*1000,pt);
Toast.makeText(TimeActivity.this,"定时器启动 触发时间"+mFormat.format(time+5*1000),Toast.LENGTH_SHORT).show();
}
});
}
效果图:
定时器广播Demo_2
当然我们可以不添加action
AndroidManifest.xml注册静态广播
<receiver
android:name=".ui.MyReceiver"
android:enabled="true"
android:exported="true">
</receiver>
创建广播class
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "定时器广播成功接收", Toast.LENGTH_SHORT).show();
}
}
创建定时器:
mBtnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mFormat = new SimpleDateFormat("yyyy年MM月dd日 : HH时mm分ss秒");
long time = System.currentTimeMillis();
Log.e(TAG, "TIME1: "+time);
Intent intent = new Intent(TimeActivity.this,MyReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(TimeActivity.this,0,intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);
manager.set(AlarmManager.RTC_WAKEUP,time+5*1000,pi);
Toast.makeText(TimeActivity.this,"定时器启动 触发时间"+mFormat.format(time+5*1000),Toast.LENGTH_SHORT).show();
}
});