1. 程式人生 > >Android鬧鐘 AlarmManager的使用

Android鬧鐘 AlarmManager的使用

 

 

 

Android鬧鐘 AlarmManager的使用

 

AlarmManager介紹

  AlarmManager這個類提供對系統鬧鐘服務的訪問介面。

  你可以為你的應用設定一個在未來某個時間喚醒的功能。

  當鬧鐘響起,實際上是系統發出了為這個鬧鐘註冊的廣播,會自動開啟目標應用。

  註冊的鬧鐘在裝置睡眠的時候仍然會保留,可以選擇性地設定是否喚醒裝置,但是當裝置關機和重啟後,鬧鐘將會被清除

 

  在alarm的receiver的onReceive()

方法被執行的時候,Alarm Manager持有一個CPU喚醒鎖,這樣就保證了裝置在處理完廣播之前不會sleep。

  一旦onReceive()方法返回,Alarm Manager就會釋放這個鎖,表明一些情況下可能onReceive()方法一執行完裝置就會sleep。

  如果你的alarm receiver中呼叫了Context.startService(),那麼很可能service還沒起來裝置就sleep了。

  為了阻止這種情況,你的BroadcastReceiver和Service需要實現不同的喚醒鎖機制,來確保裝置持續執行到service可用為止。

 

  注意:Alarm Manager主要是用來在特定時刻執行你的程式碼,即便是你的應用在那個特定時刻沒有跑的情況。

  對於常規的計時操作(ticks, timeouts, etc),使用Handler處理更加方便和有效率。

 

  另:從API 19開始,alarm的機制都是非準確傳遞,作業系統將會轉換鬧鐘,來最小化喚醒和電池使用。

  有一些新的API會支援嚴格準確的傳遞,見 setWindow(int, long, long, PendingIntent)setExact(int, long, PendingIntent)

  targetSdkVersion在API 19之前應用仍將繼續使用以前的行為

,所有的鬧鐘在要求準確傳遞的情況下都會準確傳遞。

 

鬧鐘Demo

  Android Api demos中就有關於鬧鐘使用的Demo:

  com.example.android.apis.app.AlarmController

  其中設定了兩種鬧鐘,一種是一次性的,一種是重複的。

Manifest中的宣告,process屬性

  自定義的receiver,在manifest中宣告如下:

複製程式碼
<receiver
            android:name=".OneShotAlarm"
            android:process=":remote" />
        <receiver
            android:name=".RepeatingAlarm"
            android:process=":remote" />
複製程式碼

 

  Demo中兩個Receiver的onReceive方法中顯示了各自的Toast提示,所以不再列出。

  在此討論一下process屬性,它規定了元件(activity, service, receiver等)所在的程序。

  通常情況下,沒有指定這個屬性,一個應用所有的元件都執行在應用的預設程序中,程序的名字和應用的包名一致。

  比如manifest的package="com.example.helloalarm",則預設程序名就是com.example.helloalarm

  <application>元素的process屬性可以為全部的元件設定一個不同的預設程序。

  元件可以override這個預設的程序設定,這樣你的應用就可以是多程序的。

 

  如果你的process屬性以一個冒號開頭,程序名會在原來的程序名之後附加冒號之後的字串作為新的程序名。當元件需要時,會自動建立這個程序。這個程序是應用私有的程序。

  如果process屬性以小寫字母開頭,將會直接以屬性中的這個名字作為程序名,這是一個全域性程序,這樣的程序可以被多個不同應用中的元件共享。

 

一次性鬧鐘

複製程式碼
// When the alarm goes off, we want to broadcast an Intent to our
            // BroadcastReceiver. Here we make an Intent with an explicit class
            // name to have our own receiver (which has been published in
            // AndroidManifest.xml) instantiated and called, and then create an
            // IntentSender to have the intent executed as a broadcast.
            Intent intent = new Intent(AlarmController.this, OneShotAlarm.class);
            PendingIntent sender = PendingIntent.getBroadcast(
                    AlarmController.this, 0, intent, 0);

            // We want the alarm to go off 10 seconds from now.
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(System.currentTimeMillis());
            calendar.add(Calendar.SECOND, 10);

            // Schedule the alarm!
            AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
            am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);
複製程式碼

 

重複鬧鐘

  鬧鐘設定:

複製程式碼
// When the alarm goes off, we want to broadcast an Intent to our
            // BroadcastReceiver. Here we make an Intent with an explicit class
            // name to have our own receiver (which has been published in
            // AndroidManifest.xml) instantiated and called, and then create an
            // IntentSender to have the intent executed as a broadcast.
            // Note that unlike above, this IntentSender is configured to
            // allow itself to be sent multiple times.
            Intent intent = new Intent(AlarmController.this,
                    RepeatingAlarm.class);
            PendingIntent sender = PendingIntent.getBroadcast(
                    AlarmController.this, 0, intent, 0);

            // We want the alarm to go off 10 seconds from now.
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(System.currentTimeMillis());
            calendar.add(Calendar.SECOND, 10);
            // Schedule the alarm!
            AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
            am.setRepeating(AlarmManager.RTC_WAKEUP,
                    calendar.getTimeInMillis(), 10 * 1000, sender);
複製程式碼

 

  鬧鐘取消:

複製程式碼
// Create the same intent, and thus a matching IntentSender, for
            // the one that was scheduled.
            Intent intent = new Intent(AlarmController.this,
                    RepeatingAlarm.class);
            PendingIntent sender = PendingIntent.getBroadcast(
                    AlarmController.this, 0, intent, 0);

            // And cancel the alarm.
            AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
            am.cancel(sender);
複製程式碼

 

AlarmManager說明

  AlarmManager這個類提供對系統鬧鐘服務的訪問介面。

  對它的獲取是通過系統服務:

   Context.getSystemService(Context.ALARM_SERVICE)

 

  相關方法說明:

  cancel(PendingIntent operation)方法將會取消Intent匹配的任何鬧鐘。

  關於Intent的匹配,檢視filterEquals(Intent other)方法的說明可知,兩個Intent從intent resolution(filtering)(Intent決議或過濾)的角度來看是一致的,即認為兩個Intent相等。即是說,Intent的action,data,type,class,categories是相同的,其他的資料都不在比較範圍之內。

 

  set(int type, long triggerAtMillis, PendingIntent operation)方法將會設定一個鬧鐘。

  注意:對於計時操作,可能使用Handler更加有效率和簡單。

  設定鬧鐘的時候注意:

  1.如果宣告的triggerAtMillis是一個過去的時間,鬧鐘將會立即被觸發。

  2.如果已經有一個相同intent的鬧鐘被設定過了,那麼前一個鬧鐘將會取消,被新設定的鬧鐘所代替。

 

  注意這裡說的intent相同指的都是Intent在 filterEquals(Intent)的定義下匹配。

  鬧鐘是一個廣播,接收器需要自己定義和註冊,註冊使用動態註冊( registerReceiver(BroadcastReceiver, IntentFilter) )或者靜態註冊(<receiver> tag in an AndroidManifest.xml file)都可以。 

  setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)方法將會設定一個重複性的鬧鐘。

  比set方法多了一個間隔引數。

 

  type的型別是四種:

  ELAPSED_REALTIMEELAPSED_REALTIME_WAKEUPRTCRTC_WAKEUP.

  區分的是時間標準是否在睡眠狀態下喚醒裝置

  具體檢視官方文件吧不再詳細解釋啦。

 

例項

  比如要設定一個每晚21:30喚醒的重複鬧鐘:

複製程式碼
private static final int INTERVAL = 1000 * 60 * 60 * 24;// 24h

//...


        Intent intent = new Intent(context, RequestAlarmReceiver.class);
        PendingIntent sender = PendingIntent.getBroadcast(context,
                REQUEST_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT);

        // Schedule the alarm!
        AlarmManager am = (AlarmManager) context
                .getSystemService(Context.ALARM_SERVICE);

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 21);
        calendar.set(Calendar.MINUTE, 30);
        calendar.set(Calendar.SECOND, 10);
        calendar.set(Calendar.MILLISECOND, 0);

        am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
                INTERVAL, sender);
複製程式碼

 

 

參考資料

  AlarmManager:

  http://developer.android.com/reference/android/app/AlarmManager.html

 

  鬧鐘Demo解析:

  http://blog.csdn.net/mapdigit/article/details/7644134