[Android 開發筆記] Scheduling Repeating Alarms 範例教學 (鬧鐘,定時器)

想要用Android 作鬧鐘或是定時器,就會用到此class

clock 分兩種:  "elapsed real time" 與 "real time clock" (RTC)

elapsed real time: 從開機時間開始計算

real time clock: 實際時鐘時間

兩種各別都有"wakeup" version : 如果螢幕關閉了,喚醒CPU

elapsed real time用在周期性作業上

real time clock用在特定時間點上(要注意時區問題,使用者更改時區會產生問題)

type有以下這四種:

  • ELAPSED_REALTIME—Fires the pending intent based on the amount of time since the device was booted, but doesn't wake up the device. The elapsed time includes any time during which the device was asleep.
  • ELAPSED_REALTIME_WAKEUP—Wakes up the device and fires the pending intent after the specified length of time has elapsed since device boot.
  • RTC—Fires the pending intent at the specified time but does not wake up the device.
  • RTC_WAKEUP—Wakes up the device to fire the pending intent at the specified time.

使用setInexactRepeating設定Alarm (setRepeating的省電版,但interval只能輸入規定常數)

public void setInexactRepeating (int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)

1. int type 可以輸入上述的ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC, or RTC_WAKEUP

2. triggerAtMillis 輸入第一次的時間 (1sec = 1000 millisec)

3.intervalMillis則是輸入周期,如果輸入INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_HALF_DAY, or INTERVAL_DAY,Android會自動與其他Alarm比較並對齊,減少手機wake up 的次數

4. 則是輸入要做的動作 型態為PendingIntent

ELAPSED_REALTIME_WAKEUP examples
以下範例為30分鐘後trigger,之後每30分鐘做一次

// Hopefully your alarm will have a lower frequency than this!
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
另一個範例為60秒後trigger但不重複

private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() +
        60 * 1000, alarmIntent);

RTC examples

以下範例為2:00p.m. Trigger 並且每天循環一次的Alarm(一般的鬧鐘)

// Set the alarm to start at approximately 2:00 p.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 14);
// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        AlarmManager.INTERVAL_DAY, alarmIntent);
另一個範例 8:30a.m.Trigger ,並且之後每20分鐘循環一次(貪睡鬧鐘~)

private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
// Set the alarm to start at 8:30 a.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);
// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        1000 * 60 * 20, alarmIntent);


要選擇哪一個Function ?  setInexactRepeating() or setRepeating()  ?

前述說過 setInexactRepeating() 的 interval只能輸入規定常數,Android可以達到省電目的,一般使用這個就好,除非你需要非常精準的時間(如8:30) ,那才需要用到 setRepeating() ,但就比較耗電一點

如何取消Alarm ?

cancel掉不要產生的pendingIntent即可

// If the alarm has been set, cancel it.
if (alarmMgr!= null) {
    alarmMgr.cancel(alarmIntent);
}

如何在開機時就自動開啟Alarm ?

Android預設關機後Alarm就會Cancel掉
1.加入uses-permission:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

2.實作 BroadcastReceiver :
public class SampleBootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
            // Set the alarm here.
        }
    }
}

3.manifest 設定receiver,此處anable設為false的原因在於,如果有設定Alarm再開啟,沒有則關掉,避免不必要的動作
<receiver android:name=".SampleBootReceiver"
        android:enabled="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"></action>
    </intent-filter>
</receiver>

當Alarm開啟後,開啟Receiver :
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();

pm.setComponentEnabledSetting(receiver,
        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
        PackageManager.DONT_KILL_APP);

關閉:
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();

pm.setComponentEnabledSetting(receiver,
        PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
        PackageManager.DONT_KILL_APP);

延伸:
1.定時執行除了Alarm 還有 利用  Timer and Thread   的 Handler class
2.如果考慮到定時抓取Server資訊(例如更新天氣資訊) 可以使用 Google Cloud Messaging (GCM)

資料來源: Android Dev

沒有留言:

張貼留言