Android鬧鐘服務(wù)
AlarmManager是Android系統(tǒng)提供的一種執(zhí)行定時(shí)任務(wù)的手段播急,一般適用于長時(shí)間或者需要喚醒cpu保證準(zhǔn)時(shí)的定時(shí)任務(wù),提供喚醒和非喚醒, 重復(fù)和一次性等模式。系統(tǒng)源碼中的鬧鐘app就是基于它隘竭。設(shè)備關(guān)閉或是重啟的時(shí)候會(huì)被清除。
使用方式
- 獲取AlarmManager實(shí)例
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
- 構(gòu)造一個(gè)Intent
Intent intent = new Intent(context, targetClass.class);
//intetn.setAction(action)...
- 構(gòu)造一個(gè)PendingIntent
PendingIntent PendingIntent = PendingIntent.getXXX(context, requestCode, intent, flag);
PendingIntent的getXXX方法名根據(jù)targetClass的類型替換, targetClass是除了content provider的其他組件讼渊。
大致解釋一下PendingIntent动看。它是對(duì)Intent的進(jìn)一步封裝,能夠完成更多的操作爪幻。它通過一系列g(shù)etXXX得到菱皆,其中有兩個(gè)參數(shù)比較重要:requestCode和flag。
RequestCode
有時(shí)Notification或AlarmManager會(huì)設(shè)置多個(gè)PendingIntent挨稿,PendingIntent通過requestCode區(qū)分不同仇轻,當(dāng)通過它同時(shí)設(shè)置多個(gè)操作時(shí)需要注意設(shè)置不同的requestCode,否則后設(shè)置的會(huì)把先設(shè)置的覆蓋掉叶组。
Flag
FLAG_CANCEL_CURRENT:如果當(dāng)前系統(tǒng)中已經(jīng)存在一個(gè)相同的PendingIntent對(duì)象拯田,那么就將先將已有的PendingIntent取消,然后重新生成一個(gè)PendingIntent對(duì)象。
FLAG_NO_CREATE:如果當(dāng)前系統(tǒng)中不存在相同的PendingIntent對(duì)象,系統(tǒng)將不會(huì)創(chuàng)建該P(yáng)endingIntent對(duì)象而是直接返回null赦抖。
FLAG_ONE_SHOT:該P(yáng)endingIntent只作用一次骏全。在該P(yáng)endingIntent對(duì)象通過send()方法觸發(fā)過后,PendingIntent將自動(dòng)調(diào)用cancel()進(jìn)行銷毀,那么如果你再調(diào)用send()方法的話,系統(tǒng)將會(huì)返回一個(gè)SendIntentException。
FLAG_UPDATE_CURRENT:如果系統(tǒng)中有一個(gè)和你描述的PendingIntent對(duì)等的PendingInent窃爷,那么系統(tǒng)將使用該P(yáng)endingIntent對(duì)象,但是會(huì)使用新的Intent來更新之前PendingIntent中的Intent對(duì)象數(shù)據(jù)姓蜂,例如更新Intent中的Extras按厘。
- 調(diào)用alarmManager的set方法
alarmManager.set(type, triggerAtMillis, pendingIntent);
alarmManager.setExact(type, triggerAtMillis, pendingIntent);
alarmManager.setWindow(type, startTime, lengthTime, pendingIntent);
alarmManager.setRepeating(type, triggerAtMillis, interval, pendingIntent);
alarmManager.setInExactRepeating(type, triggerAtMillis, interval, pendingIntent);
alarmManager.setAndAllowWhileIdle(type, triggerAtMillis, pendingIntent);
alarmManager.setExactAndAllowWhileIdle(type, triggerAtMillis, pendingIntent);
...
先解釋一下type參數(shù)
Type
public static final int RTC_WAKEUP = 0;// 表示鬧鐘在睡眠狀態(tài)下喚醒系統(tǒng)并執(zhí)行提示功能,絕對(duì)時(shí)間钱慢。
public static final int RTC = 1;// 睡眠狀態(tài)下不可用逮京,絕對(duì)時(shí)間。
public static final int ELAPSED_REALTIME_WAKEUP = 2;// 睡眠狀態(tài)下可用束莫,相對(duì)時(shí)間懒棉。
public static final int ELAPSED_REALTIME = 3;// 睡眠狀態(tài)下不可用,相對(duì)時(shí)間览绿。
POWER_OFF_WAKEUP策严,即使在關(guān)機(jī)后還能提醒,但是Android4.0以后就沒有了
不同鬧鐘類型對(duì)應(yīng)的任務(wù)首次時(shí)間的獲取方法:若為ELAPSED_REALTIME_WAKEUP饿敲,那么當(dāng)前時(shí)間就為 SystemClock.elapsedRealtime()妻导;若為RTC_WAKEUP,那么當(dāng)前時(shí)間就為System.currentTimeMillis()。
- 取消鬧鐘
alarmManager.cancel(PendingIntent operation);
alarmManager.cancel(AlarmManager.OnAlarmListener listener);
- 取得下一次鬧鐘
alarmManager.getNextAlarmClock();
Set方法
單次鬧鐘
1.set
set(type, triggerAtMillis, pendingIntent);
set(int type, long triggerAtMillis, String tag, AlarmManager.OnAlarmListener listener, Handler targetHandler)
第二個(gè)方法是第一個(gè)方法的變體倔韭,區(qū)別就是從觸發(fā)pendingintent變成了觸發(fā)listener回調(diào)暑脆,但和pendingintent一樣,只能和一個(gè)alarm綁定狐肢。后面的handler決定了在哪個(gè)handler中執(zhí)行回調(diào),填null則在主線程回調(diào)沥曹。
2.setExact
setExact(type, triggerAtMillis, pendingIntent);
setExact(int type, long triggerAtMillis, String tag, AlarmManager.OnAlarmListener listener, Handler targetHandler)
3.setWindow
setWindow(type, startTime, lengthTime, pendingIntent);
setWindow(int type, long windowStartMillis, long windowLengthMillis, String tag, AlarmManager.OnAlarmListener listener, Handler targetHandler)
4.setAndAllowWhileIdle
setAndAllowWhileIdle(type, triggerAtMillis, pendingIntent);
setExactAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation)
5.setAlarmClock
setAlarmClock(AlarmClockInfo, pendingIntent);
set方法提供設(shè)置一次性的鬧鐘份名,但隨著Android系統(tǒng)的完善,考慮到功耗等等因素妓美,需要更加精細(xì)地控制鬧鐘僵腺。因此提供了一些其他情況下的set方法『埃看下官方文檔的描述:
Note: Beginning with API 19 (Build.VERSION_CODES.KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, android.app.PendingIntent) and setExact(int, long, android.app.PendingIntent).
在Android api19之前辰如,set方法是精準(zhǔn)的,但在19之后贵试,為了降低頻繁喚醒cpu造成的電量浪費(fèi)琉兜,系統(tǒng)會(huì)自動(dòng)將幾個(gè)alarm放在一起觸發(fā),set方法自然也就無法保證準(zhǔn)確性毙玻。
因此Android又提供了setExact和setWindow來保證準(zhǔn)確性豌蟋。setExact保證精準(zhǔn)觸發(fā),setWindow保證在設(shè)置的時(shí)間段內(nèi)一定觸發(fā)桑滩。
然而在Android api23開始梧疲,Android加入了低電耗模式和應(yīng)用待機(jī)模式。其中低電耗模式明確指出在該模式下setExact和setWindow都會(huì)延遲執(zhí)行运准。但Android也給出了解決辦法:
標(biāo)準(zhǔn) AlarmManager 鬧鐘(包括 setExact() 和 setWindow())推遲到下一個(gè)維護(hù)期幌氮。
如果您需要設(shè)置在設(shè)備處于低電耗模式時(shí)觸發(fā)的鬧鐘,請(qǐng)使用 setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle()胁澳。
使用 setAlarmClock() 設(shè)置的鬧鐘將繼續(xù)正常觸發(fā)该互,系統(tǒng)會(huì)在這些鬧鐘觸發(fā)之前不久退出低電耗模式。
正如文檔所述听哭,setAndAllowWhileIdle和setExactAndAllowWhileIdle可以在低電耗下觸發(fā)慢洋,或者使用setAlarmClock。
setAlarmClock和setAndAllowWhileIdle基本一致陆盘,都可以在低電耗模式下喚醒普筹,持有mTriggerTime和mShowIntent(pendingIntent)兩個(gè)成員變量,是對(duì)鬧鐘事件的一個(gè)封裝隘马,getNextAlarmClock返回的就是一個(gè)AlarmClockInfo太防。
重復(fù)鬧鐘
1.setRepeating
alarmManager.setRepeating(type, triggerAtMillis, interval, pendingIntent);
2.setInExactRepeating
alarmManager.setInExactRepeating(type, triggerAtMillis, interval, pendingIntent);
這兩個(gè)方法可以重復(fù)執(zhí)行設(shè)定的pendingIntent。區(qū)別同上。
注意事項(xiàng)
7.1系統(tǒng)PendingIntent包裝的Intent不能直接設(shè)置Parcable對(duì)象蜒车,但可以放到bundle中讳嘱。經(jīng)查閱好像是6.0以上會(huì)出現(xiàn),需要注意酿愧。
Further
http://www.reibang.com/p/767412bf2af4
https://cloud.tencent.com/developer/article/1035539
https://www.cnblogs.com/leipDao/p/8203684.html