一.電池省電優(yōu)化(Doze和App Standby模式)
從Android6.0開始,系統(tǒng)提供了兩種省電功能(延長電池壽命和使用時(shí)間):Doze和App Standby
Doze和App Standby模式會(huì)延緩CPU和網(wǎng)絡(luò)活動(dòng)實(shí)現(xiàn)節(jié)能;
1.Doze模式
1.進(jìn)入Doze模式
在手機(jī)未充電,完全靜止且熄屏一段時(shí)間后,Android系統(tǒng)會(huì)自動(dòng)進(jìn)入Doze模式
2.Doze模式效果
1.網(wǎng)絡(luò)訪問被掛起
2.Wake Locks被無視
3.AlarmManager被推遲到下一個(gè)maintenance window窗口,
除非使用AlarmManager新方法: setAndAllowWhileIdle(),setExactAndAllowWhileIdle(),setAlarmClock()
4.WiFi掃描被停止
5.SyncAdapter同步工作被停止
6.JobScheduler定時(shí)任務(wù)被停止
Doze模式的五種狀態(tài)
ACTIVE: 活動(dòng)狀態(tài)
INACTIVE: 屏幕關(guān)閉進(jìn)入非活動(dòng)狀態(tài)
IDLE_PENDING: 每隔30分鐘讓App進(jìn)入預(yù)備狀態(tài)
IDLE: 空閑狀態(tài)
IDLE_MAINTENANCE:處理掛起任務(wù)
系統(tǒng)進(jìn)入Doze模式后,每隔一段時(shí)間(30分鐘)會(huì)有一小段時(shí)間(30s)供APP處理被掛起任務(wù),
但隨著時(shí)間推移,間隔時(shí)間會(huì)變長,以此減少電量消耗
3.退出Doze模式
1.手機(jī)充電
2.手機(jī)移動(dòng)
3.手機(jī)屏幕打開
2.App Standby模式
1.進(jìn)入App Standby模式
長時(shí)間未被用戶使用的App,將進(jìn)入App Standby狀態(tài)(被標(biāo)志為空閑狀態(tài))
2.退出App Standby模式
1.用戶主動(dòng)啟動(dòng)該App
2.該App有前臺(tái)進(jìn)程(前臺(tái)activity/前臺(tái)service),被其它前臺(tái)進(jìn)程啟動(dòng)
3.該App在鎖屏或通知欄有可見的Notification
4.Android設(shè)備充電時(shí),會(huì)將所有Standby狀態(tài)的App釋放,處理掛起任務(wù)
5.如果App空閑時(shí)間很長,系統(tǒng)將允許App一天一次訪問網(wǎng)絡(luò)
3.App Standby和Doze區(qū)別
App Standby不需要屏幕關(guān)閉,App進(jìn)入后臺(tái)一段時(shí)間,網(wǎng)絡(luò)也會(huì)受到限制
Doze模式需要屏幕關(guān)閉(通常晚上睡覺或長時(shí)間屏幕關(guān)閉才會(huì)進(jìn)入)
3.阻止電池優(yōu)化(白名單)
Android6.0及更高版本提供電池優(yōu)化白名單,App加入白名單可逃脫Doze和App Standby限制,
處于白名單中的App也會(huì)受到一定限制: Jobs和Syncs以及常規(guī)Alarms也會(huì)被推遲;
用戶手動(dòng)設(shè)置App進(jìn)入白名單: 設(shè)置>電池>電池優(yōu)化白名單
App檢測是否在白名單: PowerManager.isIgnoringBatteryOptimizations()
App請求加入白名單:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm != null && !pm.isIgnoringBatteryOptimizations(getPackageName())) {
//1.進(jìn)入系統(tǒng)電池優(yōu)化設(shè)置界面,把當(dāng)前APP加入白名單
//startActivity(new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS));
//2.彈出系統(tǒng)對話框,把當(dāng)前APP加入白名單(無需進(jìn)入設(shè)置界面)
//在manifest添加權(quán)限 <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
}
二.AlarmManager定時(shí)鬧鐘失效
1.App被Kill后,AlarmManager失效(只有App進(jìn)程在運(yùn)行時(shí),才會(huì)收到系統(tǒng)定時(shí)AlarmManager通知)
添加守護(hù)進(jìn)程,相互監(jiān)聽重啟; 提醒用戶加入鎖屏清理白名單
2.手機(jī)重啟,AlarmManager任務(wù)失效
監(jiān)聽重啟廣播,重新設(shè)置定時(shí)鬧鐘
3.從Android4.4(API19)開始,AlarmManager機(jī)制修改,set(),setRepeating()定時(shí)不再精確,甚至setRepeating只生效一次(不會(huì)重復(fù))
新增精確定時(shí)方法: setExact(),setWindow(),setAlarmClock(),
4.從Android6.0(API23)開始,進(jìn)入Doze模式(省電優(yōu)化),AlarmManager被延緩
新增精確定時(shí)方法: setAndAllowWhileIdle(),setExactAndAllowWhileIdle()
從Android4.4(API19)開始,新增精準(zhǔn)定時(shí)方法都是一次性鬧鐘,沒有重復(fù)定時(shí)的方法,
所以當(dāng)需要重復(fù)周期鬧鐘,只能在下一次喚醒時(shí)重新設(shè)置定時(shí),間接實(shí)現(xiàn)重復(fù)鬧鐘挥吵!
精確定時(shí)一次Demo如下:
void setWakeAtTime(Context cxt, int delay) {
PendingIntent pi = PendingIntent.getService(cxt,0,new Intent(cxt, xxService.class),PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager) cxt.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) //Android 6山宾,針對省電優(yōu)化
alarm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delay, pi);
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) //Android 4.4,針對set不準(zhǔn)確
alarm.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delay, pi);
else
alarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delay, pi);
}
簡書: http://www.reibang.com/p/585ca251b871
CSDN博客: http://blog.csdn.net/qq_32115439/article/details/78848386
GitHub博客: http://lioil.win/2017/12/19/Android-Alarm_Doze_Standby.html
Coding博客: http://c.lioil.win/2017/12/19/Android-Alarm_Doze_Standby.html