Android中的AlarmManager功能很強大,它是一個全域性定時器,可以在指定時間或者指定週期啟動其他元件(包括Activity、Service、BroadcastReceiver)。
使用AlarmManager程式設計也很簡單,只要按照以下步驟即可:
1.獲取AlarmManager物件;
2.建立PendingIntent物件;
3.設定執行任務的時間和週期。
下面將詳細介紹各個步驟:
AlarmManager是一個系統服務,在Android應用中可以通過Context物件的getSystemService()方法來獲取AlarmManager物件,如下程式碼所示:
- AlarmManager aManager=(AlarmManager)getSystemService(Service.ALARM_SERVICE);
獲取了AlarmManager物件之後就可以呼叫它的方法來設定定時啟動指定元件。
常用的有如下幾個方法:
- set(int type,long triggerAtTime,PendingIntent operation):設定在triggerAtTime時間啟動由operation引數指定的元件。
- setInexactRepeating(int type,long triggerAtTime,long interval, PendingIntent operation):設定一個非精確的週期性任務。任務近似地以interval引數指定的時間間隔執行,如果果由於某些原因(如垃圾回收或其他後臺活動)使得某一個任務延遲執行了,那麼系統就會調整後續任務的執行時間,保證不會因為一個任務的提前或滯後而影響到所有任務的執行,這樣看來,任務就沒有精確地按照interval引數指定的間隔執行。
- setRepeating(int type,long triggerAtTime,long interval,PendingIntent operation):設定一個週期性執行的定時任務,和上面的方法相比,這個方法執行的是精確的定時任務,系統會盡量保證時間間隔固定不變,如果某一個任務被延遲了,那麼後續的任務也相應地被延遲。
1. type 定時任務的型別,該參數可以接收如下值:
- ELAPSED_REALTIME:表示鬧鐘在手機睡眠狀態下不可用,該狀態下鬧鐘使用相對時間(相對於系統啟動開始)。
- ELAPSED_REALTIME_WAKEUP: 表示鬧鐘在睡眠狀態下會喚醒系統並執行提示功能,該狀態下鬧鐘也使用相對時間。
- RTC:表示鬧鐘在手機睡眠狀態下不可用,該狀態下鬧鐘使用絕對時間(即系統時間)。當系統呼叫System.currentTimeMillis()方法的返回值與triggerAtTime相等時啟動operation所對應的元件。
- RTC_WAKEUP:表示鬧鐘在睡眠狀態下會喚醒系統並執行提示功能,該狀態下鬧鐘也使用絕對時間。
2. triggerAtTime 定時任務首次觸發的時間,是一個毫秒值,該引數值的含義受type引數影響,二者具體的對應關係如下:
type | triggerAtTime |
ELAPSED_REALTIME ELAPSED_REALTIME_WAKEUP |
相對系統啟動的時間。要獲取當前時間相對系統啟動的時間用SystemClock.elapsedRealtime()方法。 例如:我想在開機一個小時後執行某個任務,那麼這裡的triggerAtTime的值就應該是1小時的毫秒值(360 0000 millis). |
RTC RTC_WAKEUP |
絕對時間,即和1970年1月1日00:00:00時間上的差值,以毫秒為單位。此時定時任務第一次觸發的條件是當系統呼叫System.currentTimeMillis()方法的返回值與triggerAtTime相等。 |
3. interval 定時任務執行的週期
4. operation 是一個PendingIntent物件,代表鬧鐘需要執行的動作,如啟動Activity、Service,傳送廣播等。
PendingIntent是Intent的封裝類,代表一個延遲執行的意圖。需要注意的是,如果希望到設定的時間啟動Service,則應該採用PendingIntent.getService(Context context, int requestCode, Intent intent, int flags)方法來獲取PendingIntent物件;如果希望到設定的時間傳送Broadcast,則PendingIntent物件的獲取就應該採用PendingIntent.getBroadcast(Context context, int requestCode, Intent intent, int flags)方法;如果希望到設定的時間啟動Activity,則PendingIntent物件的獲取就應該採用PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags)方法。如果這三種方法錯用了的話,雖然不會報錯,但是看不到鬧鐘提示效果。另外,還有一個PendingIntent.getActivities(Context context, int requestCode, Intent[] intents, int flags)方法,允許傳入一個Intent陣列,這樣就可以同時啟動多個Activity。
說了這麼多,接下來就用程式碼來演示一下吧。
- package com.example.androidtest;
- import android.os.Bundle;
- import android.app.Activity;
- import android.app.AlarmManager;
- import android.app.PendingIntent;
- import android.app.Service;
- import android.content.Intent;
- public class AlarmDemoActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_alarm_demo);
- // 獲取AlarmManager物件
- AlarmManager aManager=(AlarmManager)getSystemService(Service.ALARM_SERVICE);
- Intent intent=new Intent();
- // 啟動一個名為DialogActivity的Activity
- intent.setClass(this, DialogActivity.class);
- // 獲取PendingIntent物件
- // requestCode 引數用來區分不同的PendingIntent物件
- // flag 引數常用的有4個值:
- // FLAG_CANCEL_CURRENT 當需要獲取的PendingIntent物件已經存在時,先取消當前的物件,再獲取新的;
- // FLAG_ONE_SHOT 獲取的PendingIntent物件只能使用一次,再次使用需要重新獲取
- // FLAG_NO_CREATE 如果獲取的PendingIntent物件不存在,則返回null
- // FLAG_UPDATE_CURRENT 如果希望獲取的PendingIntent物件與已經存在的PendingIntent物件相比,如果只是Intent附加的資料不 // 同,那麼當前存在的PendingIntent物件不會被取消,而是重新載入新的Intent附加的資料
- PendingIntent pi=PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
- // 設定定時任務,這裡使用絕對時間,即使休眠也提醒,程式啟動後過1s鍾會啟動新的Activity
- aManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+1000, pi);
- }
- }
那麼問題又來了,如果設定的鬧鐘想取消怎麼辦?
很簡單,AlarmManager有一個方法cancel(PendingIntent operation),需要注意的是,這裡傳入的PendingIntent 物件必須和前面設定鬧鐘時傳入的PendingIntent 物件相等才行。兩個PendingIntent 如何才算相等?
the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags)
可見,要求還是挺嚴格的,幾乎所有的東西都要一樣,如果我們的程式中需要頻繁地設定和取消鬧鐘,我們可以把這兩個方法封裝一下,方便使用:
- /**
- * 設定提醒
- * @param context
- * @param aManager
- * @param reminder 自定義的一個實體類,封裝了提醒相關的東西,如提醒的編號ID,提醒的時間等
- */
- public static void setAlarm(Context context,AlarmManager aManager,Reminder reminder)
- {
- // 註冊AlarmManager的定時服務
- Intent intent=new Intent(Constants.ACITON_REMIND);// Constants.ACITON_REMIND是自定義的一個action
- // 使用Reminder實體的ID作為PendingIntent的requestCode可以保證PendingIntent的唯一性
- PendingIntent pi=PendingIntent.getBroadcast(context, (int)reminder.getId(), intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
- // 設定的時間是Reminder實體中封裝的時間
- aManager.set(AlarmManager.RTC_WAKEUP, reminder.getReminderDate().getTime(), pi);
- }
- /**
- * 取消提醒
- * @param context
- * @param aManager
- * @param reminder
- */
- public static void cancelAlarm(Context context,AlarmManager aManager,Reminder reminder)
- {
- // 取消AlarmManager的定時服務
- Intent intent=new Intent(Constants.ACITON_REMIND);// 和設定鬧鐘時的action要一樣
- // 這裡PendingIntent的requestCode、intent和flag要和設定鬧鐘時一樣
- PendingIntent pi=PendingIntent.getBroadcast(context, (int)reminder.getId(), intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
- aManager.cancel(pi);
- }
在使用AlarmManager的時候還有幾點需要注意:
1. 鬧鐘在關機或重啟之後會失效。如果希望鬧鐘一直有效,先把鬧鐘資訊儲存到本地,然後開機啟動一個Service,通過Service重新設定鬧鐘。
2. 如果鬧鐘設定的時間小於當前時間,那麼鬧鐘事件會立即觸發,如果想避免這種情況,可以在設定鬧鐘之前先新增一個判斷,判斷需要設定的時間如果小於當前時間則什麼也不做。
3. 後續再發現需要注意的問題會繼續補充……
轉載請指明原文出處http://blog.csdn.net/fxdaniel/article/details/41150129