Android利用AlarmManager執行定時任務


Android中的AlarmManager功能很強大,它是一個全局定時器,可以在指定時間或者指定周期啟動其他組件(包括Activity、Service、BroadcastReceiver)。

使用AlarmManager編程也很簡單,只要按照以下步驟即可:

1.獲取AlarmManager對象;

2.創建PendingIntent對象;

3.設定執行任務的時間和周期。

下面將詳細介紹各個步驟:

AlarmManager是一個系統服務,在Android應用中可以通過Context對象的getSystemService()方法來獲取AlarmManager對象,如下代碼所示:

[java] view plain copy
  1. 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。

說了這么多,接下來就用代碼來演示一下吧。

[java] view plain copy
  1. package com.example.androidtest;  
  2.   
  3. import android.os.Bundle;  
  4. import android.app.Activity;  
  5. import android.app.AlarmManager;  
  6. import android.app.PendingIntent;  
  7. import android.app.Service;  
  8. import android.content.Intent;  
  9.   
  10. public class AlarmDemoActivity extends Activity {  
  11.   
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_alarm_demo);  
  16.         // 獲取AlarmManager對象  
  17.         AlarmManager aManager=(AlarmManager)getSystemService(Service.ALARM_SERVICE);  
  18.         Intent intent=new Intent();  
  19.         // 啟動一個名為DialogActivity的Activity  
  20.         intent.setClass(this, DialogActivity.class);  
  21.         // 獲取PendingIntent對象  
  22.         // requestCode 參數用來區分不同的PendingIntent對象  
  23.         // flag 參數常用的有4個值:  
  24.         //      FLAG_CANCEL_CURRENT 當需要獲取的PendingIntent對象已經存在時,先取消當前的對象,再獲取新的;  
  25.         //  FLAG_ONE_SHOT 獲取的PendingIntent對象只能使用一次,再次使用需要重新獲取  
  26.         //  FLAG_NO_CREATE 如果獲取的PendingIntent對象不存在,則返回null  
  27.         //  FLAG_UPDATE_CURRENT 如果希望獲取的PendingIntent對象與已經存在的PendingIntent對象相比,如果只是Intent附加的數據不      //  同,那么當前存在的PendingIntent對象不會被取消,而是重新加載新的Intent附加的數據  
  28.         PendingIntent pi=PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);  
  29.         // 設置定時任務,這里使用絕對時間,即使休眠也提醒,程序啟動后過1s鍾會啟動新的Activity  
  30.         aManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+1000, pi);  
  31.     }  
  32. }  

那么問題又來了,如果設定的鬧鍾想取消怎么辦?

很簡單,AlarmManager有一個方法cancel(PendingIntent operation),需要注意的是,這里傳入的PendingIntent 對象必須和前面設定鬧鍾時傳入的PendingIntent 對象相等才行。兩個PendingIntent 如何才算相等?

the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags)

可見,要求還是挺嚴格的,幾乎所有的東西都要一樣,如果我們的程序中需要頻繁地設定和取消鬧鍾,我們可以把這兩個方法封裝一下,方便使用:

[java] view plain copy
  1. /** 
  2.      * 設定提醒 
  3.      * @param context 
  4.      * @param aManager 
  5.      * @param reminder 自定義的一個實體類,封裝了提醒相關的東西,如提醒的編號ID,提醒的時間等 
  6.      */  
  7.     public static void setAlarm(Context context,AlarmManager aManager,Reminder reminder)  
  8.     {  
  9.           
  10.         // 注冊AlarmManager的定時服務  
  11.         Intent intent=new Intent(Constants.ACITON_REMIND);// Constants.ACITON_REMIND是自定義的一個action  
  12.   
  13.         // 使用Reminder實體的ID作為PendingIntent的requestCode可以保證PendingIntent的唯一性  
  14.         PendingIntent pi=PendingIntent.getBroadcast(context, (int)reminder.getId(), intent,  
  15.                 PendingIntent.FLAG_UPDATE_CURRENT);  
  16.         // 設定的時間是Reminder實體中封裝的時間  
  17.         aManager.set(AlarmManager.RTC_WAKEUP, reminder.getReminderDate().getTime(), pi);  
  18.     }  
  19.     /** 
  20.      * 取消提醒 
  21.      * @param context 
  22.      * @param aManager 
  23.      * @param reminder 
  24.      */  
  25.     public static void cancelAlarm(Context context,AlarmManager aManager,Reminder reminder)  
  26.     {  
  27.         // 取消AlarmManager的定時服務  
  28.         Intent intent=new Intent(Constants.ACITON_REMIND);// 和設定鬧鍾時的action要一樣  
  29.   
  30.         // 這里PendingIntent的requestCode、intent和flag要和設定鬧鍾時一樣  
  31.         PendingIntent pi=PendingIntent.getBroadcast(context, (int)reminder.getId(), intent,  
  32.                 PendingIntent.FLAG_UPDATE_CURRENT);  
  33.         aManager.cancel(pi);  
  34.     }  

在使用AlarmManager的時候還有幾點需要注意:

1. 鬧鍾在關機或重啟之后會失效。如果希望鬧鍾一直有效,先把鬧鍾信息存儲到本地,然后開機啟動一個Service,通過Service重新設定鬧鍾。

2. 如果鬧鍾設定的時間小於當前時間,那么鬧鍾事件會立即觸發,如果想避免這種情況,可以在設定鬧鍾之前先添加一個判斷,判斷需要設定的時間如果小於當前時間則什么也不做。

3. 后續再發現需要注意的問題會繼續補充……


轉載請指明原文出處http://blog.csdn.net/fxdaniel/article/details/41150129


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM