在Android中,可以使用鬧鐘管理器來觸發事件,包括廣播BroadcastReceiver,服務Service和活動Activity。這些事件可以在特定的時刻或者以固定的時間間隔來觸發。
使用鬧鐘管理器一般有以下幾個步驟:
1、擷取到鬧鐘管理器的服務,即AlarmManager;
2、确定設定鬧鐘的時刻;
3、建立要調用的接收程式,可以是廣播BroadcastReceiver,服務Service和活動Activity;
4、建立一個挂起的Intent(即PendingIntent),它可傳遞給鬧鐘管理器來調用設定的該接收程式;
5、使用第2步中的時間和第4步中的Intent來設定鬧鐘;
6、在第3步中的接收鬧鐘管理器的調用。
接下來是對每個步驟進行說明:
1、擷取鬧鐘管理器,AlarmManager
這是比較簡單的,調用系統服務就可以得到AlarmManager。
AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
2、建立鬧鐘的時刻
為了快捷友善,特别建立了一個Utils類,在裡面提供建立各種類型的時刻。
public class Utils
{
/**
* 建立secs秒後鬧鐘時間
* @param secs
* @return
*/
public static Calendar getTimeAfterInSecs(int secs)
{
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND,secs);
return cal;
}
public static Calendar getCurrentTime()
{
Calendar cal = Calendar.getInstance();
return cal;
}
/**
* 建立在某個固定小時時刻的鬧鐘
* @param hours
* @return
*/
public static Calendar getTodayAt(int hours)
{
Calendar today = Calendar.getInstance();
Calendar cal = Calendar.getInstance();
cal.clear();
int year = today.get(Calendar.YEAR);
int month = today.get(Calendar.MONTH);
//represents the day of the month
int day = today.get(Calendar.DATE);
cal.set(year,month,day,hours,0,0);
return cal;
}
public static String getDateTimeString(Calendar cal)
{
SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss");
df.setLenient(false);
String s = df.format(cal.getTime());
return s;
}
}
3、建立接受鬧鐘的接收程式,這裡暫時使用一種類型BroadCastReceiver
public class TestReceiver extends BroadcastReceiver
{
private static final String tag = "TestReceiver";
@Override
public void onReceive(Context context, Intent intent)
{
Log.d("TestReceiver", "intent=" + intent);
String message = intent.getStringExtra("message");
Log.d(tag, message);
}
}
4、建立鬧鐘的PendingIntent
首先需要建立隻想TestReceiver的Intent
Intent intent = new Intent(mContext, TestReceiver.class);
intent.putExtra("message", "Single Shot Alarm");
接下來建立挂起的PendingIntent:
PendingIntent pi =
PendingIntent.getBroadcast(
mContext, //context
1, //request id, used for disambiguating this intent
intent, //intent to be delivered
PendingIntent.FLAG_ONE_SHOT); //pending intent flags
5、設定鬧鐘
Calendar cal = Utils.getTimeAfterInSecs(30);
AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi);
這樣就可以在TestReiver中接收到鬧鐘消息了。
以上是關于鬧鐘管理器的簡單使用,接下來将增加關于設定重複鬧鐘和取消鬧鐘的使用。
一、設定重複鬧鐘
設定重複鬧鐘的前面幾個步驟都是一樣的,隻是在最後設定鬧鐘的時候有所變化
am.setRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
5*1000, //5 secs
pi);
關于這個方法的參數說明:第一個:警報的類型,這裡采用鬧鐘來喚醒裝置;第二個:第一次鬧鐘執行的時刻;第三個:在鬧鐘第一次執行後,每隔多久開始重複執行;第四個:挂起的PendingIntent。
二、取消鬧鐘
要取消鬧鐘,必須首先挂起一個Intent,然後調用cancel()方法,将參數傳遞給鬧鐘管理器。
Intent intent =
new Intent(this.mContext, TestReceiver.class);
//To cancel, extra is not necessary to be filled in
//intent.putExtra("message", "Repeating Alarm");
PendingIntent pi = this.getDistinctPendingIntent(intent, 2);
// Schedule the alarm!
AlarmManager am =
(AlarmManager)
this.mContext.getSystemService(Context.ALARM_SERVICE);
am.cancel(pi);
protected PendingIntent getDistinctPendingIntent(Intent intent, int requestId)
{
PendingIntent pi =
PendingIntent.getBroadcast(
mContext, //context
requestId, //request id
intent, //intent to be delivered
0);
//pending intent flags
//PendingIntent.FLAG_ONE_SHOT);
return pi;
}
在建立Intent的時候,如果是為了取消鬧鐘,可以不用再Intent中設定任何消息參數和資料,隻需要保證最後的指向接收程式一緻。然後建立的PendingIntent也必須和原來一緻,必須確定采用設定鬧鐘時相同的方式來構造它,包括請求代碼,即上面的requestId和接收程式。
三、設定多個鬧鐘
如果了解了上面關于設定單個鬧鐘和重複鬧鐘的設定過程,可能會認為隻需要建立多個不同的cal時刻,然後分别設定到鬧鐘裡面,就能實作了。其實不然,裡面涉及到一些陷進。
先看下面的代碼:
/*
* Same intent cannot be scheduled multiple times.
* If you do, only the last one will take affect.
*
* Notice you are using the same request id.
*/
public void scheduleSameIntentMultipleTimes()
{
//Get the instance in time that is
//30 secs from now.
Calendar cal = Utils.getTimeAfterInSecs(30);
Calendar cal2 = Utils.getTimeAfterInSecs(35);
Calendar cal3 = Utils.getTimeAfterInSecs(40);
Calendar cal4 = Utils.getTimeAfterInSecs(45);
//If you want to point to 11:00 hours today.
//Calendar cal = Utils.getTodayAt(11);
//Get an intent to invoke
//TestReceiver class
Intent intent = new Intent(mContext, TestReceiver.class);
intent.putExtra("message", "Single Shot Alarm");
PendingIntent pi = this.getDistinctPendingIntent(intent, 1);
// Schedule the alarm!
AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi);
am.set(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), pi);
am.set(AlarmManager.RTC_WAKEUP, cal3.getTimeInMillis(), pi);
am.set(AlarmManager.RTC_WAKEUP, cal4.getTimeInMillis(), pi);
}
上面這部分代碼,使用了同一個PendingIntent,設定了4個不同的鬧鐘時間,這樣的效果就是: 隻有最後一個鬧鐘會被觸發,前面的所有鬧鐘都會被忽略掉。
而要實作多個鬧鐘的實作是如下:
/*
* Same intent can be scheduled multiple times
* if you change the request id on the pending intent.
* Request id identifies an intent as a unique intent.
*/
public void scheduleDistinctIntents()
{
//Get the instance in time that is
//30 secs from now.
Calendar cal = Utils.getTimeAfterInSecs(30);
Calendar cal2 = Utils.getTimeAfterInSecs(35);
Calendar cal3 = Utils.getTimeAfterInSecs(40);
Calendar cal4 = Utils.getTimeAfterInSecs(45);
//If you want to point to 11:00 hours today.
//Calendar cal = Utils.getTodayAt(11);
//Get an intent to invoke
//TestReceiver class
Intent intent = new Intent(mContext, TestReceiver.class);
intent.putExtra("message", "Single Shot Alarm");
// Schedule the alarms!
AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), getDistinctPendingIntent(intent,1));
am.set(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), getDistinctPendingIntent(intent,2));
am.set(AlarmManager.RTC_WAKEUP, cal3.getTimeInMillis(), getDistinctPendingIntent(intent,3));
am.set(AlarmManager.RTC_WAKEUP, cal4.getTimeInMillis(), getDistinctPendingIntent(intent,4));
}
每個挂起的Intent,也就是PendingIntent不同,也就是讓每個PendingIntent的RequestId不同。産生這種原因是因為在AlarmManager中設定鬧鐘時,對于相同的Intent,是通過不同的請求Id來建立的。
在相同類型的Intent上設定鬧鐘時,隻有最後一個鬧鐘時生效的。
以下是AlarmMangerService的部分源碼,可以看到為什麼不能使用相同的PendingIntent了。
public void setRepeating(int type, long triggerAtTime, long interval,
PendingIntent operation) {
.....
synchronized (mLock) {
Alarm alarm = new Alarm();
alarm.type = type;
alarm.when = triggerAtTime;
alarm.repeatInterval = interval;
alarm.operation = operation;
// Remove this alarm if already scheduled.
removeLocked(operation); //當使用相同的operation的時候u,就會先把已有的删除,這樣的話,直到最後一個才會生效。
if (localLOGV) Slog.v(TAG, "set: " + alarm);
int index = addAlarmLocked(alarm);
if (index == 0) {
setLocked(alarm);
}
}
}
最後一點是關于鬧鐘的持久化問題,它們是不能儲存到裝置重新啟動之後,也就是說當裝置重新啟動後,之前設定的鬧鐘将全部失效。
下面是一個詳細的鬧鐘例子,可以作為參考
http://pan.baidu.com/s/1kTHlOG3
下面是關于android中鬧鐘的調用流程,知道進入到Android的底層,可以看看:
http://blog.csdn.net/crycheng/article/details/7804813