更好的閱讀體驗(yàn):https://www.zybuluo.com/zhuhf/note/680897
為了節(jié)省系統(tǒng)資源(內(nèi)存、電量、流量等)科吭,提升手機(jī)流暢度和用戶體驗(yàn),Android O 對(duì)程序“后臺(tái)運(yùn)行”的限制變得更加嚴(yán)格猴鲫,具體體現(xiàn)在兩個(gè)方面:
- 限制后臺(tái)服務(wù)
當(dāng)我們的程序處于“空閑”狀態(tài)对人,“后臺(tái)服務(wù)”會(huì)被限制執(zhí)行,但是這不影響“前臺(tái)服務(wù)”拂共。
- 限制廣播
程序不能在Manifest中注冊(cè)“限制性”廣播牺弄,但仍然可以動(dòng)態(tài)的去注冊(cè)。
注意:如果 targetSdkVersion <= 25宜狐,則不受以上兩個(gè)限制势告。
限制后臺(tái)服務(wù)
系統(tǒng)將一個(gè) App 分為“前臺(tái)”和“后臺(tái)”兩種狀態(tài)蛇捌。當(dāng)滿足下面任意一個(gè)條件,則認(rèn)為是“前臺(tái)” App:
擁有可見(jiàn)的 Activity咱台,狀態(tài)為 started 或 paused
擁有一個(gè)“foreground Service”
有一個(gè)處于前臺(tái)的 App “連接”到了當(dāng)前 App络拌,一般通過(guò)“bind service” 或 “content provider”
如果以上三個(gè)條件沒(méi)有一個(gè)滿足,則認(rèn)為它是“后臺(tái)” App回溺。
當(dāng) App 在“前臺(tái)”春贸,它可以隨意的創(chuàng)建和啟動(dòng)一個(gè)“前臺(tái)”或者“后臺(tái)” Service。當(dāng) App 切換到“后臺(tái)”后遗遵,它將有一小段時(shí)間仍然可以使用 Service萍恕,在這之后 App 便會(huì)處于“空閑”狀態(tài)。這個(gè)時(shí)候车要,系統(tǒng)會(huì)停止 App 的所有“后臺(tái)” Service允粤,這就好像 App 自己調(diào)用了 Service.stopSelf()
方法。
在一些特定情況下屯蹦,“后臺(tái)” App 在一小段時(shí)間內(nèi)也可以沒(méi)有限制的使用 Service维哈。這種“特定”情況,包含以下幾種:
- 處理 FCM 消息
這是谷歌自己的消息推送系統(tǒng)登澜,不過(guò)在國(guó)內(nèi)無(wú)法使用阔挠。
接收到廣播消息,比如 SMS 信息等
執(zhí)行 notification 的 PendingIntent
那么脑蠕,我們?nèi)绾谓鉀Q App “后臺(tái)”運(yùn)行時(shí)的諸多限制呢购撼?
谷歌提供了兩種建議的方案:
- 使用 JobScheduler 替代 Service 來(lái)執(zhí)行“周期性”任務(wù)
關(guān)于 JobScheduler 的使用請(qǐng)參考這里。
- 使用“前臺(tái)” Service
Android O 之前谴仙,創(chuàng)建“前臺(tái)” Service 的步驟:
先使用
startService()
方法啟動(dòng)一個(gè) Service迂求;然后使用
Service.startForeground()
方法將 Service 設(shè)置為“前臺(tái)” 。
這樣在通知欄就會(huì)顯示一個(gè) notification 晃跺,表明 Service 是“前臺(tái)”服務(wù)揩局。
然而,Android O 建議我們使用 NotificationManager.startServiceInForeground()
方法來(lái)創(chuàng)建一個(gè)“前臺(tái)” Service掀虎。這樣做的好處是凌盯,當(dāng) App 處于“后臺(tái)”時(shí),我們是無(wú)法使用 startService()
來(lái)創(chuàng)建 Service烹玉,但卻可以在 廣播 和 JobScheduler 中使用 NotificationManager.startServiceInForeground()
來(lái)創(chuàng)建 Service驰怎。
限制廣播
在 Android 7.0 (API level 24) 之后,谷歌已經(jīng)對(duì)廣播做了很多限制二打,具體表現(xiàn)為:
targetSdkVersion >= 24县忌,Manifest 中聲明
CONNECTIVITY_ACTION
的廣播將無(wú)法收到通知。但如果是在代碼中注冊(cè),則不受此影響症杏。不能發(fā)送和接收
ACTION_NEW_PICTURE
和ACTION_NEW_VIDEO
這兩種類型的廣播装获,這個(gè)影響所有的 App,與聲明的 targetSdkVersion 無(wú)關(guān)鸳慈。
而 Android O 讓廣播的限制變得更加嚴(yán)格饱溢,它將廣播分為“implicit”和“explicit”兩種類型。
舉個(gè)例子:
- 如果有 App 安裝了新版本走芋,那么
ACTION_PACKAGE_REPLACED
將會(huì)發(fā)送給所有注冊(cè)了此廣播的 App绩郎,而不是某一個(gè)指定的 App,所以我們稱它為 “implicit”翁逞。 - 而
ACTION_MY_PACKAGE_REPLACED
只會(huì)發(fā)送給指定的 App蔬充,所以稱它為“explicit”鸣峭。
具體限制表現(xiàn)為:
Android O 不允許在 Manifest 中注冊(cè)“implicit”類型的廣播,但可以注冊(cè)“explicit”類型的廣播。
仍然可以在代碼中使用
Context.registerReceiver()
注冊(cè)“implicit”和“explicit”類型的廣播喳坠。
“explicit” 類型的廣播目前有以下幾種:
- ACTION_LOCKED_BOOT_COMPLETED,
ACTION_BOOT_COMPLETED - ACTION_USER_INITIALIZE
- ACTION_TIMEZONE_CHANGED
- CTION_LOCALE_CHANGED
- ACTION_USB_ACCESSORY_ATTACHED, ACTION_USB_ACCESSORY_DETACHED,
ACTION_USB_DEVICE_ATTACHED,
ACTION_USB_DEVICE_DETACHED - ACTION_HEADSET_PLUG
- ACTION_CONNECTION_STATE_CHANGED, ACTION_CONNECTION_STATE_CHANGED
- ACTION_CARRIER_CONFIG_CHANGED
- ACTION_DEVICE_STORAGE_LOW,
ACTION_DEVICE_STORAGE_OK - LOGIN_ACCOUNTS_CHANGED_ACTION
- ACTION_PACKAGE_DATA_CLEARED
- ACTION_PACKAGE_FULLY_REMOVED
- ACTION_NEW_OUTGOING_CALL
- ACTION_DEVICE_OWNER_CHANGED
- ACTION_EVENT_REMINDER
更多詳細(xì)信息請(qǐng)參考這里暴氏。
解決方案:
比如你有一個(gè)應(yīng)用在收到系統(tǒng)“充電廣播”的時(shí)候執(zhí)行一些清理動(dòng)作厅贪, 然而 ACTION_POWER_CONNECTED
屬于“implicit”類型廣播山涡,所以你無(wú)法在 Android O 中使用。
你可以使用以下兩個(gè)建議方案:
- 使用
JobScheduler
來(lái)替代“特定”的廣播必怜,比如手機(jī)充電廣播:ACTION_POWER_CONNECTED
- 使用
Context.registerReceiver()
注冊(cè)“implicit”廣播肉拓,而不是在 Manifest 中注冊(cè)
以上就是 Android O 對(duì)“后臺(tái)”運(yùn)行諸多限制的介紹,同時(shí)提供了一些建議性解決方案梳庆,希望能夠幫到大家~