最近在進行的備忘錄項目需要用到定時提醒,用鬧鐘服務是再好不過了的選擇,但是之前只是在看入門書籍的時候模模糊糊地抄了一遍代碼,到現(xiàn)在早就忘得一干二凈了,只好再次利用強大的搜索引擎重新學習一番。
設置時間
用戶可以給需要提示的便簽設置指定的時間。說到設置時間,就是TimePicker和DatePicker了,暫時不考慮這兩個原生控件是否美觀,實現(xiàn)功能優(yōu)先(因為太菜)。可是這倆我也沒怎么接觸過,翻翻官方Guide把。
TimePicker
TimePicker是用來選擇時間的,只有小時和分鐘兩個單位,在不同的API版本上有著不同的視覺效果,官方給的建議是自己建立一個類繼承DialogFragment在onCreateDialog方法內(nèi)返回一個TimePickerDialog。官方都這么說了,那就這么來把。
public class TimePickerDialogFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR_OF_DAY); // 選擇器的初始小時值
int minute = c.get(Calendar.MINUTE); // 選擇器的初始分鐘值
return new TimePickerDialog(getActivity(), this, hour, minute, true); // 最后一個參數(shù)是選擇是否使用24小時為單位,true為是
}
// 當對話框關閉后執(zhí)行
@Override
public void onTimeSet(TimePicker timePicker, int i, int i1) {
// 進行時間設定
}
DatePicker
DatePicker與TimePicker類似,官網(wǎng)都是推薦通過DialogFragment來生成
public static class DatePickerFragment extends DialogFragment
implements DatePickerDialog.OnDateSetListener {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// 設置DatePicker上的默認值
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
// 生成DatePicker
return new DatePickerDialog(getActivity(), this, year, month, day);
}
public void onDateSet(DatePicker view, int year, int month, int day) {
// 進行日期設定
}
}
設置鬧鐘
既然時間設置好了,下面就是重頭戲,通過用戶設定的時間來設置鬧鐘。這個類不能直接new來實例化。
鬧鐘是系統(tǒng)的一種服務,通過AlarmManager這個類來管理。AlarmManager可以通過context.getSystem(ALARM_SERVICE)來獲取。AlarmManager使用的場景如下:你需要讓你的程序代碼能夠在某一個特定時刻被執(zhí)行,而不考慮程序目前的是否在運行。如果想要實現(xiàn)通常的定時操作,使用Handler會更簡單。
從API 19(KITKAT)開始,鬧鐘喚醒的時間是不準確的:系統(tǒng)為了減少喚醒和電量使用會對鬧鐘時間進行一定的偏移。提供了新的APIs來支持那些需要準時喚醒的應用,可以參考
setWidndow(int, long, long, PendingIntent)和setExtact(int, long, PendingIntent),API版本低于19的應用還可以使用之前的API且那些API保證喚醒是準時的
鬧鐘的喚醒方式
在AlarmManager類里面有幾個常量,定義了鬧鐘的喚醒方式
- AlarmManager.ELAPSED_REALTIME: 采用的時間值一個相對值,以機器的開機時間為0時間點,假如到了設定的時間點但是機器是息屏狀態(tài)時,鬧鐘服務無法執(zhí)行。
- AlarmManager.ELAPSED_REALTIME_WAKEUP:采用的時間值和ELAPSED_REALTIME相同,但是可以在息屏狀態(tài)下喚醒機器。
- AlarmManager.RTC:采用的時UTC時間,即與機器的開機時間無關。無法在息屏狀態(tài)下運行服務。
- AlarmManager.RTC_WAKEUP:在RTC的前提下增加了息屏喚醒的功能。
常用的方法
在API小于19的機器上,我們可以使用set(int type, long triggerAtMills, PendingIntent operation)方法就可以設定一個鬧鐘了,參數(shù)名字很好理解,type就是上面提到的鬧鐘的喚醒方式,通常使用RTC_WAKEUP,triggerAtMills參數(shù)我們需要從TimePicker中獲取,可以在onTimeSet接口中將用戶設定的時間值保存在一個Calendar對象中,之后通過getTimeInMills獲取時間賦值給triggerAtMills就行了。operation參數(shù)我理解為執(zhí)行鬧鐘服務時需要喚醒的東西,可以是一個Activity,也可以是Service或Broadcast。比如我要在鬧鐘執(zhí)行時喚醒ClockActivity這個Activity,只需要寫類似下面的代碼就可以生成一個operation
Intent clock = new Intent(this, ClockActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
在API大于19的機器上,如果要執(zhí)行鬧鐘服務準時,需要的方法是setExact(int type, long triggerAtMills, PendingIntent operation,這個方法的參數(shù)和set方法一樣,就不再重復了。還一個方法是setWindow(int type, long windowStartMills, long windowLengthMills, PendingIntent operation),其中windowStartMills和triggerAtMills是一個東西,這個方法的一個特點在于能通過windowLengthMills參數(shù)控制服務運行的時間
最后
鬧鐘部分還有一些其他的功能和坑,如重復定時,用戶重啟機器等,因為暫時沒有使用,暫不寫在文中,以后踩了坑的話會來更新這篇文章。