在開發中,可能會遇到一種需求是固定在某個時間點將資料強制更新:
告訴管家,我要早上七點起床,並請主廚幫我煮好早餐
該怎麼實作呢?
環境
- Mac @Mojave
- Homebrew @2.2.17
- Android Studio
- Android SDK 21
拆解狀況
以上的句子,可以拆分出四大重點: a) 管家 b) 時間 c) 主廚 d) 煮早餐
尋找管家
Android 本身已提供了 AlarmManager
Class
在初始化時必須告知系統,我們需要 Alarm service(一位管家)
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
指定時間
Java 存在三種與時間有關的 Class
java.util.Calendar -> 最常使用
java.sql.Timestamp -> 大多使用在 SQLite 記錄時間上(字串型態:yyyy-MM-dd hh:mm:ss.SSS)
java.util.Date -> 主要用來作為 Calendar Class 與 String Class 的轉換
在此我們使用 Calendar 來作為指定時間的工具
Calendar calendar = Calendar.getInstance(); -> 初始化 Calendar,TimeZone 以裝置為主
calendar.add(Calendar.DATE, 1);
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
以此例子加以補充:
a) 如果想要指定某地區的時區(例如台灣)
你可以這樣做: Calendar.getInstance(TimeZone.getTimeZone("Asia/Taipei"), Locale.TAIWAN)
b) .add 代表 以目前時間為主再做增減
(以上述例子來看:天數 add 1
= 明天)
c) .set 代表 直接指定絕對時間
(以上述例子來看:分鐘 set 59
= 59 分)
可以兜出完整的設定為
明天 23:59:59
指定主廚
Android 本身提供了 BroadcastReceiver
Class 來讓我們使用
其實需要做的就是告訴它 時間到了它要做什麼事情
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 補充:在此我建議可以先使用 intent 取得 bundle,建立一些確認機制,避免過度複雜在此就不多加解釋
煮早餐();
}
}
}
主廚設定好之後 我必須告訴管家要指定哪位主廚 而我與管家溝通的橋樑是 PendingIntent
PendingIntent pi = PendingIntent.getBroadcast(
context, -> Activiy(父容器)
0, -> RequestCode(可隨意自訂)
new Intent(context, AlarmReceiver.class), -> 主廚(剛剛創建的)
PendingIntent.FLAG_UPDATE_CURRENT -> PendingIntent 創建規則
);
關於 PendingIntent 創建方式可參考官方文件:
https://developer.android.com/reference/android/app/PendingIntent.html
我這次使用的 `FLAG_UPDATE_CURRENT` 也是較常使用的
意指當今天相同的 PendingIntent 已存在時,新的並不會取代舊的,但會取代 intent 內的 extra data
串接
準備好了管家 am、時間 calendar、主廚 AlarmReceiver、橋樑 pi 後 來和管家做最後的溝通
am.set(
AlarmManager.RTC_WAKEUP, -> 鬧鐘類型
calendar.getTimeInMillis(), -> 透過 calendar 取得 milliseconds
pi -> PendingIntent(內含 AlarmReceiver)
);
關於 AlarmManager 鬧鐘類型可參考官方文件:
https://developer.android.com/reference/android/app/AlarmManager.html
我這次使用的 `RTC_WAKEUP` 意指在指定時間會被觸發並喚醒裝置
做完囉! 各位可以設個短一點的時間來做測試。
備註
最後,讓我們試著回顧最一開始的故事,並帶入曾做過的名詞: 我告訴(PendingIntent)管家(AlarmManager) 我要早上七點起床(Calendar) 並請主廚(BroadcastReceiver) 幫我煮好早餐 (Action)