一切黔、App 定時(shí)提醒方案
1啥辨、Handler:?通過(guò)Handler的setMessageDelay()來(lái)實(shí)現(xiàn)定時(shí)發(fā)送消息的功能介返。但是Handler依賴于所在線程焕妙,線程結(jié)束就起不到定時(shí)效果蒋伦。
2、Timer:?可以精確的做到定時(shí)操作焚鹊,但是手機(jī)滅屏后長(zhǎng)時(shí)間不使用痕届,CPU就進(jìn)入休眠模式。使用Timer定時(shí)就會(huì)失敗 末患,Timer無(wú)法喚醒CPU
3研叫、AlarmManager:?是Android的全局定時(shí)器,就是指定時(shí)間做一件事情(封裝在PendingIntent)璧针。通過(guò)PendingIntent的getActivity()嚷炉、getService()、getBroadcast()來(lái)執(zhí)行具體探橱。和Timer的區(qū)別是:Timer可能因?yàn)槭謾C(jī)休眠而被殺掉申屹,但是AlarmManager可以做到喚醒手機(jī)??
二、AlarmManager
概述
AlarmManger提供了對(duì)系統(tǒng)定時(shí)服務(wù)的訪問(wèn)接口隧膏,使得開發(fā)者可以安排在未來(lái)某個(gè)時(shí)間運(yùn)行應(yīng)用哗讥。當(dāng)?shù)竭_(dá)鬧鐘設(shè)定時(shí)間,系統(tǒng)廣播鬧鐘之前注冊(cè)的Intent胞枕。如果此時(shí)應(yīng)用還沒(méi)有啟動(dòng)杆煞,系統(tǒng)還會(huì)幫你自動(dòng)啟動(dòng)目標(biāo)應(yīng)用。即使設(shè)置進(jìn)入睡眠腐泻,已注冊(cè)的鬧鐘具有喚醒CPU的功能决乎,可以保證每次需要執(zhí)行特定的任務(wù)時(shí)CPU都能正常工作。喚醒CPU的功能是AlarmManager和Timer最大的區(qū)別派桩。
鬧鐘的類型
RTC_WAKEUP: 使用System.currentTimeMillis(),能夠喚醒設(shè)備
RTC: 使用Systent.currentTimeMillis(),不能夠喚醒設(shè)備
ELAPSED_REALTIME:使用系統(tǒng)啟動(dòng)的時(shí)間瑞驱,不能夠喚醒設(shè)備。設(shè)備喚醒后發(fā)送出去
ELAPSED_REALTIME_WAKEUP:使用系統(tǒng)啟動(dòng)時(shí)間窄坦,能夠喚醒設(shè)備唤反。
一凳寺、分類
基于時(shí)間分類
1、基于絕對(duì)時(shí)間設(shè)置鬧鐘(系統(tǒng)當(dāng)前時(shí)間System.currentTimeMillis())
2彤侍、基于相對(duì)時(shí)間設(shè)置鬧鐘(系統(tǒng)運(yùn)行時(shí)長(zhǎng)SystemClock.elapsedRealtime())
是否可以喚醒CPU
1肠缨、CPU在睡眠狀態(tài)下,可喚醒設(shè)備(RTC_WAKEUP:絕對(duì)時(shí)間盏阶,ELAPSED_REALTIME_WAKEUP:相對(duì)時(shí)間)
2晒奕、不能喚醒設(shè)備,設(shè)備被喚醒后才能發(fā)出鬧鐘(RTC:絕對(duì)時(shí)間名斟,ELAPSED_REALTIME:相對(duì)時(shí)間)
二脑慧、設(shè)置鬧鐘API
1、void set(int type,long triggerAtMillis,PendingIntent operation)
? ? ? ? ? ? ?type: 類型
? ? ? ? ? ? ?triggerAtMillis:定時(shí)時(shí)間
? ? ? ? ? ? ?operation:定時(shí)執(zhí)行的任務(wù)
add API 1
? ? ? ? ? 用于設(shè)置一次性的鬧鐘砰盐,在API 19之后為鬧鐘不準(zhǔn)確闷袒。API小于19的設(shè)備是精準(zhǔn)的。PS:因在API 19Android系統(tǒng)會(huì)將時(shí)間相近鬧鐘任務(wù)進(jìn)行批量處理岩梳,將設(shè)備的"喚醒"次數(shù)降到最低囊骤,并將電池的使用降到最低。
2冀值、void set(int type,long triggerAtMillis,AlarmManager.OnAlarmListener listener,Handler targetHandler)
? ? ? ? ? ? ?type:類型
? ? ? ? ? ? ?triggerAtMillis:定時(shí)時(shí)間
? ? ? ? ? ? ?listener: 定時(shí)任務(wù)的回調(diào)
? ? ? ? ? ? ?targetHandler: 任務(wù)回調(diào)線程的Handler,為null在主線程
add API 24
? ? ? ? ? ? 和方法1作用是一致的也物,唯一的區(qū)別是定時(shí)任務(wù)處理位置不同
總結(jié):方法1和2在API19之后是不精準(zhǔn)的,且在低功耗下不執(zhí)行
3列疗、void setExact(int type,long triggerAtMillis,PendingIntent operation)
? ? ? ? ? ? ?type: 鬧鐘類型
? ? ? ? ? ? ?triggerAtMillis:定時(shí)時(shí)間
? ? ? ? ? ? ?operation: 定時(shí)執(zhí)行的任務(wù)
add API 19
? ? ? ? ? ? 在規(guī)定的時(shí)間準(zhǔn)時(shí)執(zhí)行
? ? ? ? ? ? 官方提示:對(duì)于不必要的強(qiáng)烈需求精準(zhǔn)的鬧鐘滑蚯,沒(méi)有必要使用此方法。該方法會(huì)降低系統(tǒng)的最小化電池使用能力抵栈。
4膘魄、void setExact(int type,long triggerAtMillis,String tag,AlarmManger.OnAlarmListener listener,Handler targetHandler)
? ? ? ? ? ? type:鬧鐘類型
? ? ? ? ? ? triggerAtMillis:定時(shí)時(shí)間
? ? ? ? ? ? tag:監(jiān)聽(tīng)器的Tag
? ? ? ? ? ? listener:鬧鐘的定時(shí)任務(wù)回調(diào)
? ? ? ? ? ? targetHandler:定時(shí)任務(wù)回調(diào)執(zhí)行的線程的Handler,null在主線程中執(zhí)行
add API 24
? ? ? ? ? ? 同方法3一致,回調(diào)結(jié)果位置不同竭讳。
? ??5、void setAlarmClock(AlarmManager.AlarmClockInfo info,PendingIntent operation)
? ? ? ? ? ? ? ? ?info: 鬧鐘參數(shù)封裝類
? ? ? ? ? ? ? ? ?operation: 定時(shí)任務(wù)的回調(diào)
add API 21
? ? ? ? ? ? ?像方法3浙踢,但是type設(shè)置為RTC_WAKEUP
總結(jié):方法3绢慢、4、5 是精準(zhǔn)的洛波。5支持在低功耗模式下也執(zhí)行胰舆,3、4需要驗(yàn)證
6蹬挤、void setInexactRepeating(int type,long triggerAtMillis,long intervalMillis,PendingIntent operation)
? ? ? ? ? ? ?type: 鬧鐘類型
? ? ? ? ? ? ?triggerAtMillis: 首次執(zhí)行時(shí)間缚窿,不會(huì)執(zhí)行之前的時(shí)間。若首次不執(zhí)行焰扳,之后的重復(fù)定時(shí)任務(wù)也將不執(zhí)行
? ? ? ? ? ? ?intervalMillis:重復(fù)執(zhí)行的間隔時(shí)間
? ? ? ? ? ? ?operation: 定時(shí)任務(wù)的回調(diào)
add API 3
? ? ? ? ? ? 設(shè)置重復(fù)鬧鐘倦零,不準(zhǔn)確的误续。比方法7更省電。不會(huì)執(zhí)行請(qǐng)求之前的定時(shí)任務(wù)扫茅,而且之后的任務(wù)都不會(huì)執(zhí)行蹋嵌。雖然會(huì)重復(fù)執(zhí)行,但執(zhí)行間隔時(shí)間不同葫隙。
7栽烂、void setRepeating(int type,long triggerAtMillis,long intervalMillis,PendingIntent operation)
? ? ? ? ? ? ?type: 鬧鐘類型
? ? ? ? ? ? ?triggerAtMillis: 首次執(zhí)行時(shí)間
? ? ? ? ? ? ?intervalMillis:重復(fù)執(zhí)行的間隔時(shí)間
? ? ? ? ? ? ?operation: 定時(shí)任務(wù)的回調(diào)
add API 1
? ? ? ? ? ? 在API19之前是精準(zhǔn)的。功能同方法6一致恋脚。
總結(jié):方法6腺办、7都是設(shè)置重復(fù)鬧鐘的,setRepeating更為精準(zhǔn)糟描。如果一個(gè)鬧鐘被延遲(比如系統(tǒng)休眠怀喉、非喚醒CPU類型的鬧鐘)。手機(jī)喚醒后會(huì)盡快回調(diào)一個(gè)鬧鐘蚓挤,之后按照原間隔時(shí)間執(zhí)行磺送。例如你設(shè)置整點(diǎn)鬧鐘,然后手機(jī)在7:45到8:45在休眠灿意,當(dāng)8:45喚醒手機(jī)后會(huì)盡快回調(diào)一個(gè)鬧鐘估灿,然后在9點(diǎn)在回調(diào)一個(gè)鬧鐘。
在API19之后所有的重復(fù)鬧鐘都是不精確的缤剧。
8馅袁、void setAndAllowWhileIdle(int type,long triggerAtMillis,PendingIntent operation)
? ? ? ? ? ? ?type: 鬧鐘類型
? ? ? ? ? ? ?triggerAtMillis: 執(zhí)行時(shí)間
? ? ? ? ? ? ?operation: 回調(diào)
add API 23(23之后才引入了低功耗和應(yīng)用待機(jī)模式)
? ? ? ? ? ?類似方法1,但是即使在系統(tǒng)處于低功耗模式下荒辕,也允許發(fā)出鬧鐘汗销。這種類型的鬧鐘僅被用于必須在實(shí)際需要在低功耗時(shí)發(fā)出鬧鐘的場(chǎng)景。當(dāng)鬧鐘發(fā)出后抵窒,該應(yīng)用程序還會(huì)被系統(tǒng)添加到臨時(shí)白名單中弛针,持續(xù)大約10s中。以便該程序獲取更多的喚醒鎖李皇,從而完成其工作削茁。但是當(dāng)設(shè)備處于低功耗模式下,該鬧鐘會(huì)嚴(yán)重影響設(shè)備的電量使用掉房。系統(tǒng)為了減少濫用茧跋,對(duì)特定程序發(fā)出鬧鐘的頻率進(jìn)行了限制。在正常的系統(tǒng)下(非低功耗模式下)鬧鐘間隔時(shí)間不能小于1分鐘卓囚,低于1分中瘾杭,鬧鐘不會(huì)發(fā)出,在低功耗模式下哪亿,時(shí)間間隔不能小于15分鐘粥烁。
? ? ? ? ? 像set()方法1一樣贤笆,鬧鐘會(huì)被批量處理,也就是說(shuō)鬧鐘不是精準(zhǔn)的
9页徐、void setExactAndAllowWhileIdle(int type,long triggerAtMillis,PendingIntent operation)
? ? ? ? ? ? type: 鬧鐘類型
? ? ? ? ? ? triggerAtMillis:執(zhí)行時(shí)間
? ? ? ? ? ? operation:回調(diào)
add API 23
? ? ? ? ? ?類似setExact()(方法3)苏潜,設(shè)置一次性精準(zhǔn)鬧鐘。但它比方法8更精準(zhǔn)变勇。
總結(jié): 允許在低功耗模式執(zhí)行鬧鐘
注意:setAndAllowWhileIdle() 和 setExactAndAllowWhileIdle() 為每個(gè)應(yīng)用觸發(fā)鬧鐘的頻率都不能超過(guò)每 9 分鐘一次恤左。
10、void setWindow(int type,long windowStartMillis,long windowLengthMillis,PendingIntent operation)
? ? ? ? ? ? ? ?type: 鬧鐘類型
? ? ? ? ? ? ? ?windowStartMillis: 鬧鐘發(fā)出的最早時(shí)間
? ? ? ? ? ? ? ?windowLengthMillis: 鬧鐘需要在多久的是時(shí)間段內(nèi)發(fā)出
? ? ? ? ? ? ? ?operation: 鬧鐘的回調(diào)
add API 19
? ? ? ? ? ? 設(shè)置在某一個(gè)時(shí)間段內(nèi)發(fā)出鬧鐘搀绣,對(duì)鬧鐘的及時(shí)性要求不高飞袋。它允許程序利用分批的方式來(lái)處理。這樣即是對(duì)電池的優(yōu)化链患,他對(duì)鬧鐘的準(zhǔn)確性要求不高巧鸭。
11、void setWindow(int type,long windowStartMillis,long windowLengthMillis,String tag,AlarmManager.OnAlarmListener listener,Handler targetHandler)
app API 24
同方法10一樣麻捻,區(qū)別是鬧鐘的回調(diào)不同
總結(jié): 設(shè)置在某個(gè)時(shí)間段內(nèi)的鬧鐘纲仍,對(duì)準(zhǔn)確性要求不高
12、void cancel(PendingIntent operation)
? ? ? ? ? ? ? ?operation: 之前設(shè)置鬧鐘的Intent,這個(gè)參數(shù)必須不為null
add API 1
? ? ? ? ? ? ? 取消任何具有匹配意圖的鬧鐘贸毕。任何類型的鬧鐘郑叠,只要其意圖匹配都將被取消
13、void cancel(AlarmManager.Listener listener)
? ? ? ? ? ? ? ?listener: 要移除的鬧鐘監(jiān)聽(tīng)器
add API 24
? ? ? ? ? ? ? ?取消任何發(fā)給該listener的鬧鐘
14明棍、AlarmManager.AlarmClockInfo getNextAlarmClock()
? ? ? ? ? ? ? AlarmManager.AlarmClockInfo: 下個(gè)即將到來(lái)的鬧鐘事件乡革。如果沒(méi)有,返回null
add API 21
? ? ? ? ? ? ? ? 獲取下一個(gè)鬧鐘信息摊腋,所考慮的鬧鐘僅是通過(guò)setAlarmClock()設(shè)置的鬧鐘沸版。
15、void setTime(long millis)
? ? ? ? ? ? ? ?millis: 系統(tǒng)時(shí)間
add API 8
? ? ? ? ? ? ? ?設(shè)置系統(tǒng)時(shí)間兴蒸,需要Manifest.permission.SET_TIME權(quán)限
16视粮、void setTimeZone(String timeZone)
? ? ? ? ? ? ? ?timeZone:時(shí)區(qū)ID
add API 1
? ? ? ? ? ? ? ? 設(shè)置系統(tǒng)默認(rèn)時(shí)區(qū),需要Manifest.permission.SET_TIME_ZONE權(quán)限
三橙凳、常用的時(shí)間常量
public static final long INTERVAL_FIFTEEN_MINUTES = 15 * 60 * 1000;
public static final long INTERVAL_HALF_HOUR = 2*INTERVAL_FIFTEEN_MINUTES;
public static final long INTERVAL_HOUR = 2*INTERVAL_HALF_HOUR;
public static final long INTERVAL_HALF_DAY = 12*INTERVAL_HOUR;
public static final long INTERVAL_DAY = 2*INTERVAL_HALF_DAY;
四蕾殴、使用同一個(gè)Intent,設(shè)置多個(gè)鬧鐘僅會(huì)有最后一個(gè)生效的問(wèn)題
? ? ? ? ? 可以給每一個(gè)鬧鐘設(shè)置一個(gè)ID,保證id的唯一性就可以,這樣取消時(shí)也可以根據(jù)id關(guān)閉鬧鐘痕惋。
五、不同SDK版本使用鬧鐘的注意事項(xiàng)
SDK API < 19
? ? ? ? ?正常使用set() 娃殖、setRepeating()即可(19以下未添加鬧鐘批量處理值戳、和系統(tǒng)低功耗模式)
SDK API >=19 && SDK API < 23
? ? ? ? ?要求精準(zhǔn)的鬧鐘,需要使用setExact()(19之后系統(tǒng)為了省電炉爆,添加鬧鐘批量處理堕虹,導(dǎo)致原設(shè)置的不精準(zhǔn))
? ? ? ? ?重復(fù)鬧鐘卧晓,需要在鬧鐘回調(diào)中再次設(shè)置鬧鐘
SDK >= 23
? ? ? ? ? Android 6.0映入了低功耗模式和應(yīng)用待機(jī)模式,