Android O對應(yīng)用在后臺運(yùn)行時(shí)可以執(zhí)行的操作施加了限制,稱為后臺執(zhí)行限制(Background Execution Limits)
窿克,這可以大大減少應(yīng)用的內(nèi)存使用和耗電量骏庸,提高用戶體驗(yàn)。后臺執(zhí)行限制分為兩個(gè)部分:后臺服務(wù)限制(Background Service Limitations)年叮、 廣播限制(BroadcastLimitations)
具被。
后臺服務(wù)限制
除了下面情況外都是后臺應(yīng)用:
- 具有可見的Activity
- 具有前臺服務(wù)
- 另一個(gè)前臺應(yīng)用已關(guān)聯(lián)到該應(yīng)用(通過bindService或者使用該應(yīng)用的ContentProvider)。
應(yīng)用在后臺期間保留其后臺服務(wù)的能力將受到限制只损。如果應(yīng)用處于后臺時(shí)調(diào)用了startService()
將會拋出IllegalStateException
一姿,除非:
-
應(yīng)用已經(jīng)處于前臺,則可以調(diào)用
startService()
跃惫,不會拋出IllegalStateException
叮叹,但一旦進(jìn)入后臺,后臺應(yīng)用將被置于一個(gè)臨時(shí)白名單中爆存,位于白名單中時(shí)蛉顽,在這段時(shí)間內(nèi),應(yīng)用可以無限制地啟動服務(wù)先较,其后臺服務(wù)也可以運(yùn)行
蜂林。但這個(gè)時(shí)間期一過(Nexus 5X 8.0 系統(tǒng)上測試不到1分鐘)遥诉,應(yīng)用就會進(jìn)入空閑狀態(tài)拇泣,后臺服務(wù)就會被銷毀噪叙。
因此,通過startservices啟動的服務(wù)有如下特點(diǎn):
- 在后臺運(yùn)行的服務(wù)在幾分鐘內(nèi)會被stop掉(模擬器測試在1分鐘左右后被kill掉)霉翔。在這段時(shí)間內(nèi)睁蕾,應(yīng)用仍可以創(chuàng)建和使用服務(wù)。
- 在應(yīng)用處于后臺幾分鐘后(模擬器測試1分鐘左右)债朵,應(yīng)用將不能再通過startService創(chuàng)建后臺服務(wù)子眶,如果創(chuàng)建則拋出以下異常
Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.example.xxxx.test/.TestService }: app is in background
也就是說,當(dāng)你的應(yīng)用不在前臺序芦,時(shí)間窗結(jié)束后臭杰,會變成閑置狀態(tài),系統(tǒng)就殺死你的后臺服務(wù)谚中。網(wǎng)上一系列Service笨矢耍活,創(chuàng)建永不停止Service宪塔,經(jīng)過驗(yàn)證磁奖,都已失效。即你無法在使用后臺服務(wù)在后臺偷偷執(zhí)行需要長時(shí)間的任務(wù)某筐,例如監(jiān)控GPS狀態(tài)比搭,記錄步數(shù)等等。限制后臺服務(wù)使用的原因是南誊,當(dāng)你的app使用服務(wù)在后臺運(yùn)行時(shí)身诺,你的app消耗了寶貴的資源:- 內(nèi)存 - 電池。最佳的做法是:操作完成后抄囚,服務(wù)應(yīng)自行停止霉赡。許多應(yīng)用程序具有長時(shí)間運(yùn)行的后臺服務(wù),這些服務(wù)基本上運(yùn)行無限時(shí)間以維持與服務(wù)器的Socket連接或監(jiān)視某些任務(wù)或用戶活動怠苔。這些服務(wù)會導(dǎo)致電池耗盡同廉,并且還會不斷消耗內(nèi)存。鑒于以上原因:后臺服務(wù)已經(jīng)無法再在后臺執(zhí)行長時(shí)間任務(wù)柑司。安卓推出了以下方案來解決此類問題:
前臺服務(wù)Android 8.0 引入了一種全新的方法迫肖,即Context.startForegroundService(),以在前臺啟動新服務(wù)攒驰。在系統(tǒng)創(chuàng)建服務(wù)后蟆湖,應(yīng)用有五秒的時(shí)間來調(diào)用該服務(wù)的startForeground() 方法以顯示新服務(wù)的用戶可見通知。如果應(yīng)用在此時(shí)間限制內(nèi)未調(diào)用
startForeground()玻粪,則系統(tǒng)將停止服務(wù)并聲明此應(yīng)用為 ANR隅津。WorkManager:WorkManager適用于那些即使應(yīng)用程序退出诬垂,系統(tǒng)也能夠保證這個(gè)任務(wù)正常運(yùn)行的場景,比如將應(yīng)用程序數(shù)據(jù)上傳到服務(wù)器伦仍。它不適用于應(yīng)用進(jìn)程內(nèi)的后臺工作结窘,如果應(yīng)用進(jìn)程消失,就可以安全地終止充蓝。
JobScheduler: JobScheduler 作業(yè)替換后臺服務(wù)隧枫。 例如,CoolPhotoApp需要檢查用戶是否已經(jīng)從朋友那里收到共享的照片谓苟,即使該應(yīng)用未在前臺運(yùn)行官脓。
前臺服務(wù)
對于需要立即運(yùn)行并且必須執(zhí)行完畢的由用戶發(fā)起的工作,請使用前臺服務(wù)涝焙。使用前臺服務(wù)可告知系統(tǒng)應(yīng)用正在執(zhí)行重要任務(wù)卑笨,不應(yīng)被終止。前臺服務(wù)通過通知欄中的不可關(guān)閉通知向用戶顯示仑撞。
- 修改啟動方式
Intent service = new Intent(this, MyBackgroundService.class);
service.putExtra("startType", 1);
if (Build.VERSION.SDK_INT >= 26) {
startForegroundService(service);
} else {
startService(service);
}
- 啟動完前臺service, 一定記得在5s以內(nèi)要執(zhí)行startForeground方法赤兴,不然就會出現(xiàn)ANR。
public class MyBackgroundServiceextends Service {
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//適配安卓8.0
String channelId = getChannelId() + "";
String channelName = getChannelName();
NotificationChannel channel = new NotificationChannel(channelId, channelName,
NotificationManager.IMPORTANCE_MIN);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
startForeground(getChannelId(), getNotification());
}
}
...
}
一樣還是先判斷系統(tǒng)版本, 如果高于26就調(diào)用startForeground方法好了, 使用startForegroundService 方法啟動后臺service這么使用即可派草。不過這樣會在通知欄里面彈出彈出通知搀缠。
WorkManager
WorkManager適用于那些即使應(yīng)用程序退出,系統(tǒng)也能夠保證這個(gè)任務(wù)正常運(yùn)行的場景近迁,比如將應(yīng)用程序數(shù)據(jù)上傳到服務(wù)器艺普。它不適用于應(yīng)用進(jìn)程內(nèi)的后臺工作,如果應(yīng)用進(jìn)程消失鉴竭,就可以安全地終止
WorkManager 不適用于需要在特定時(shí)間觸發(fā)的任務(wù)歧譬,也不適用立即任務(wù)。針對特定時(shí)間觸發(fā)的任務(wù)使用 AlarmManager搏存,立即執(zhí)行的任務(wù)使用 ForegroundService瑰步。
WorkManager適用于那些在應(yīng)用退出之后任務(wù)還需要繼續(xù)執(zhí)行的需求(比如應(yīng)用數(shù)據(jù)上報(bào)服務(wù)器的情況),對應(yīng)那些在應(yīng)用退出的之后任務(wù)也需要終止的情況就需要選擇ThreadPool璧眠、AsyncTask來實(shí)現(xiàn)缩焦。
對于可延遲的工作以及預(yù)計(jì)即使您的設(shè)備或應(yīng)用重啟也會運(yùn)行的工作,請使用 WorkManager责静。WorkManager 是一個(gè) Android 庫袁滥,可在滿足工作的條件(例如網(wǎng)絡(luò)可用性和電源)時(shí)妥善運(yùn)行可延遲的后臺工作。
WorkManager 提供向后兼容的 API(兼容 API 級別 14 及更高級別)灾螃,利用 JobScheduler
API(API 級別 23 及更高級別)幫助優(yōu)化更低級別設(shè)備上的電池續(xù)航時(shí)間题翻、批量作業(yè)以及 AlarmManager
和 BroadcastReceiver
的組合。
WorkManager是一個(gè)用于排隊(duì)可延遲工作的庫腰鬼,保證在滿足約束條件后的某個(gè)時(shí)間執(zhí)行嵌赠。 WorkManager允許觀察工作狀態(tài)和創(chuàng)建復(fù)雜工作鏈的能力塑荒。
WorkManager旨在通過為系統(tǒng)驅(qū)動的后臺處理提供一流的API來簡化開發(fā)人員體驗(yàn)。它適用于即使應(yīng)用程序不再位于前臺也應(yīng)運(yùn)行的后臺作業(yè)姜挺。在可能的情況下齿税,它使用JobScheduler或Firebase JobDispatcher來完成工作; 如果你的應(yīng)用程序在前臺,它甚至?xí)L試直接在你的過程中完成工作初家。
應(yīng)用場景:每15分鐘跟蹤用戶位置
WorkManager 和AsyncTask, ThreadPool, RxJava的區(qū)別:這三個(gè)和WorkManager并不是替代的關(guān)系. 這三個(gè)工具, 能幫助你在應(yīng)用中開后臺線程干活, 但是應(yīng)用一被殺或被關(guān)閉, 這些工具就干不了活了. 而WorkManager不是, 它在應(yīng)用被殺, 甚至設(shè)備重啟后仍能保證你安排給他的任務(wù)能得到執(zhí)行.
定義 Worker
咱們定義 MainWorker 繼承 Worker偎窘,發(fā)現(xiàn)須要重寫 doWork 方法,而且須要返回任務(wù)的狀態(tài) WorkerResult:
class MainWorker : Worker() {
override fun doWork(): WorkerResult {
// 要執(zhí)行的任務(wù)
return WorkerResult.SUCCESS
}
}
定義 WorkRequest
在 MainActivity 中定義 WorkRequest:
val request = OneTimeWorkRequest.Builder(MainWorker::class.java).build()
OneTimeWorkRequest 意味著這個(gè)任務(wù)只需執(zhí)行一遍溜在。
加入任務(wù)隊(duì)列
要讓任務(wù)執(zhí)行,須要將 WorkRequest 加入任務(wù)隊(duì)列:
WorkManager.getInstance().enqueue(request)
AlarmManager
如果您需要在確切的時(shí)間運(yùn)行某項(xiàng)作業(yè)他托,請使用 AlarmManager
掖肋。AlarmManager
會在您指定的時(shí)間啟動應(yīng)用(如有必要),以便運(yùn)行該作業(yè)赏参。但是志笼,如果您的作業(yè)不需要在確切的時(shí)間運(yùn)行,則 WorkManager
是更好的選擇把篓;WorkManager
能更好地平衡系統(tǒng)資源纫溃。例如,如果您需要大約每小時(shí)運(yùn)行一次某項(xiàng)作業(yè)韧掩,但不需要在特定時(shí)間運(yùn)行該作業(yè)紊浩,則應(yīng)使用 WorkManager
設(shè)置周期性作業(yè)。
DownloadManager
如果您的應(yīng)用執(zhí)行長時(shí)間運(yùn)行的 HTTP 下載疗锐,請考慮使用 DownloadManager坊谁。客戶端可能會請求將 URI 下載到位于應(yīng)用進(jìn)程之外的特定目標(biāo)文件中滑臊。內(nèi)容下載管理器會在后臺執(zhí)行下載操作口芍,它負(fù)責(zé)處理 HTTP 互動,在下載失敗或連接發(fā)生更改以及系統(tǒng)重新啟動后重新嘗試下載雇卷。
后臺任務(wù)選擇
場景 | 推薦 |
---|---|
需系統(tǒng)觸發(fā)鬓椭,不必完成 | ThreadPool + Broadcast |
需系統(tǒng)觸發(fā),必須完成关划,可推遲 | WorkManager |
需系統(tǒng)觸發(fā)小染,必須完成,立即 | ForegroundService + Broadcast |
不需系統(tǒng)觸發(fā)祭玉,不必完成 | ThreadPool |
不需系統(tǒng)觸發(fā)氧映,必須完成,可推遲 | WorkManager |
不需系統(tǒng)觸發(fā)脱货,必須完成岛都,立即 | ForegroundService |
Android Jetpack - 使用 WorkManager 管理后臺任務(wù)
Android后臺Service已死 WorkManager崛起
Android P后臺服務(wù)被終止律姨,創(chuàng)建永不終止的后臺服務(wù)
Android后臺任務(wù)
學(xué)習(xí)Android Jetpack? 實(shí)戰(zhàn)和教程這里全都有!
Android Jetpack - 使用 WorkManager 管理后臺任務(wù)