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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章