您的位置:首页 > 移动开发 > Android开发

Android AlarmManager实现多个定时重复提醒

2012-09-18 16:29 459 查看
在移动开发中,我们经常需要实现一些定时提醒的功能,提醒功能有些定时的,像闹钟一样,有些是根据业务逻辑触发的,这里我主要说一下怎样实现多个定时提醒的实现方法。大言不惭的说下,我在做项目时遇到这个问题再中文网站没有找到任何有意义的相关文章,所以我才会在这里给广大网友分享我的经验!

多次定时重复提醒主要用到的类是AlarmManager(官方API说明),简单说下AlarmManager就是,它能够提供应用系统闹钟服务的接口,允许你的应用在未来某一时间点做某件事。这个类属于系统服务,所以其初始化如下

AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);


官方API中,该类的方法并不是很多

Public Methods
voidcancel(PendingIntent operation)
Remove any alarms with a matching
Intent
.
voidset(int type, long triggerAtMillis, PendingIntent operation)
Schedule an alarm.
voidsetInexactRepeating(int
type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
Schedule a repeating alarm that has inexact trigger time requirements; for example, an alarm that repeats every hour, but not necessarily at the top of every hour.
voidsetRepeating(int
type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
Schedule a repeating alarm.
voidsetTime(long millis)
Set the system wall clock time.
voidsetTimeZone(String timeZone)
Set the system default time zone.
我们可以看到,第2,3,4个方法是具体的设置提醒的方法,其中都需要一个PendingIntent operation的参数,这就是我们所要做的具体的操作,一般来说,都是用pendingIntent来发送一个广播或者启动一个服务,这里我选择发送一个广播

PendingIntent的初始化是整个功能的最重点,官方API提供的初始化方法有这些:

static PendingIntent, int)]getActivities(Context context,
int requestCode, Intent[] intents, int flags)
Like
getActivity(Context,
int, Intent, int)
, but allows an array of Intents to be supplied.
static PendingIntent, int, android.os.Bundle)]getActivities(Context context,
int requestCode, Intent[] intents, int flags, Bundle options)
Like
getActivity(Context,
int, Intent, int)
, but allows an array of Intents to be supplied.
static PendingIntentgetActivity(Context context,
int requestCode, Intent intent, int flags)
Retrieve a PendingIntent that will start a new activity, like calling
Context.startActivity(Intent)
.
static PendingIntentgetActivity(Context context,
int requestCode, Intent intent, int flags, Bundle options)
Retrieve a PendingIntent that will start a new activity, like calling
Context.startActivity(Intent)
.
static PendingIntentgetBroadcast(Context context,
int requestCode, Intent intent, int flags)
Retrieve a PendingIntent that will perform a broadcast, like calling
Context.sendBroadcast()
.
static PendingIntentgetService(Context context,
int requestCode, Intent intent, int flags)
Retrieve a PendingIntent that will start a service, like calling
Context.startService()
.
由于PendingIntent是系统级服务,其初始化就是系统目前管理的PendingIntent列表中取出。就拿getBroadcast(Context context,
int requestCode, Intent intent,
int flags)为例,如果列表中有相同的,则取出的就是已经注册过的PendingIntent,否则就会注册一个新的。


public static PendingIntent getBroadcast (Context context,
int requestCode, Intent intent, int flags)

Since: API Level 1

Retrieve a PendingIntent that will perform a broadcast, like calling
Context.sendBroadcast()
.

Parameters
contxtThe Context in which this PendingIntent should perform the broadcast.
reque stCodePrivate request code for the sender (currently not used).
intentThe Intent to be broadcast.
flagsMay be
FLAG_ONE_SHOT
,
FLAG_NO_CREATE
,
FLAG_CANCEL_CURRENT
,
FLAG_UPDATE_CURRENT
,
or any of the flags as supported by
Intent.fillIn()
to
control which unspecified parts of the intent that can be supplied when the actual send happens.
Returns

Returns an existing or new PendingIntent matching the given parameters. May return null only if
FLAG_NO_CREATE
has
been supplied.

第三个参数是要广播的Intent动作,第四个参数是个flags标签,简单说一下这俩个参数:

1.intent:intent就是你想要广播的内容,将数据用bundle进行封装,用intent.putExtras(Bundle bundle)方法进行传递。需要注意的是,如果是相同的intent的话,将这个intent作 为参数传进PendingIntent的时候,创建的PendingIntent是已经注册过的pendingIntent,也就是说是已经用这个PendingIntent注册过的广播不会有任何变化,比如说修 改这个广播的触发时间。那么,我们怎么判断俩个Intent是否相同呢,谷歌为我们提供了以下方法


public boolean filterEquals (Intent other)

Since: API Level 1

Determine if two intents are the same for the purposes of intent resolution (filtering). That is, if their action, data, type, class, and categories are the same. This does notcompare any
extra data included in the intents.

Parameters
otherThe other Intent to compare against.
Returns

Returns true if action, data, type, class, and categories are the same.

也就是说我们只能通过改变Intent的 action, data, type, class, and categories这5个属性来改变,后面一句更重要:This does not compare any extra data
included in the intents,这并不比较任何intent中的额外数据!!通常情况下,android中传递数据时我们都是intent的额外数据的相关方法,比如下面的代码
Intent intent = new Intent(MyBroadcastReceiver.REMIND_BROADCAST);
Bundle bundle = new Bundle();
bundle.putString("hour", hour1);
Intent intent = new Intent(MyBroadcastReceiver.REMIND_BROADCAST);
Bundle bundle = new Bundle();
bundle.putString("hour", hour2);
这俩个intent作为参数传入pendingIntent时,操作的同一个已经注册的广播!

那么,是不是改变了上面说的5个属性中的一个的话就能得到不同的pendingIntent呢?很遗憾,我试验过5个属性,都不能使PendingIntent的equals (Object otherObj)方法返回false(这个方法下面会讲),当然,这也有可能是我的方法有误,广大网友可以指正!

2.flags:看官方API的解释,点这里

这里主要说一下FLAG_UPDATE_CURRENT这个参数,上面我们说过改变intent的参数不会改变对应的pendingIntent注册的广播,如果我们只改
变了intent的额外数据而又想改变广播的内容的话,我们可以把用这个标签。上面的代码改写成这样

Intent intent = new Intent(MyBroadcastReceiver.REMIND_BROADCAST);
Bundle bundle = new Bundle();
bundle.putString("hour", hour2);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
这样就可以改变用该pendingIntent注册的广播的内容了

那么怎么判断俩个PendingIntent是否一样,谷歌也提供了专门的方法


public boolean equals (Object otherObj)

Since: API Level 1

Comparison operator on two PendingIntent objects, such that true is returned then they both represent the same operation from the same package. This allows you to use
getActivity(Context,
int, Intent, int)
,
getBroadcast(Context,
int, Intent, int)
, or
getService(Context,
int, Intent, int)
multiple times (even across a process being killed), resulting in different PendingIntent objects but whose equals() method identifies them as being the same operation.

Parameters
otherObjthe object to compare this instance with.
Returns

true
if the specified object is equal to this
Object
;
false
otherwise.

关于这个方法,我的理解是(可能有些偏差),如果俩个PendingIntent的操作是相同的,那么就是同一个PendingIntent,那么该方法返回的应该是true,如果不是,那么应该是false,经过我用代码的验证,不管是第三个参数Intent还是第四个参数,都不会影响到该方法返回的结果,都是true!那这样我们到底怎样才能创建出不同的pendingInent呢,这是我做项目的时候最头疼的一个问题了,后来我只能去强大的stackoverflow寻找答案了,幸运的是,果然被我找到了(我找到的方法),简单的说就是通过设置第二个参数来得到唯一的pendingIntent,第二个参数可以理解为id!在这里我不得不吐槽一下谷歌,尼玛API上明明写的是currently
not used啊!!!!!国外友人对用系统时间来设置这个ID,但我不建议这样,因为我们用注册了广播实现了提醒功能后,肯定要给用户一个可以取消这种提醒的设置,如果用系统时间的话,我们还必须把当时的系统时间存储起来,这并不是很方便!

上Demo的主要代码:

private void setReminder(boolean b, int data) {
Intent intent = new Intent(MyBroadcastReceiver.REMIND_BROADCAST);
Bundle bundle = new Bundle();
bundle.putInt("data", data);
intent.putExtras(bundle);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
int uniqueRequestCode = (int)System.currentTimeMillis();
PendingIntent pi = PendingIntent.getBroadcast(this, uniqueRequestCode,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (b) {
am.setRepeating(AlarmManager.RTC, 0, 60000, pi);
} else {
am.cancel(pi);
}
}


根据自己项目的需要,改变参数列表和uniqueRequestCode的值,要取消之前已经注册的广播,所传入的uniqueRequestCode必须是一样的!!要设置多个广播,只需改变uniqueRequestCode的值再次执行该方法即可

不知道为什么我上传的源码显示不出来,只好放一个115网盘的下载链接了http://115.com/file/beg2mbgw



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: