Android 后臺任務(wù)Services铝噩、WorkManager總結(jié)

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)用:

  1. 具有可見的Activity
  2. 具有前臺服務(wù)
  3. 另一個(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):

  1. 在后臺運(yùn)行的服務(wù)在幾分鐘內(nèi)會被stop掉(模擬器測試在1分鐘左右后被kill掉)霉翔。在這段時(shí)間內(nèi)睁蕾,應(yīng)用仍可以創(chuàng)建和使用服務(wù)。
  2. 在應(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)閉通知向用戶顯示仑撞。

  1. 修改啟動方式
Intent service = new Intent(this, MyBackgroundService.class);
service.putExtra("startType", 1);
if (Build.VERSION.SDK_INT >= 26) {
    startForegroundService(service);
} else {
    startService(service);
}
  1. 啟動完前臺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è)以及 AlarmManagerBroadcastReceiver 的組合。

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ù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末臼疫,一起剝皮案震驚了整個(gè)濱河市择份,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌烫堤,老刑警劉巖荣赶,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鸽斟,居然都是意外死亡拔创,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門富蓄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剩燥,“玉大人,你說我怎么就攤上這事立倍∶鸷欤” “怎么了?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵口注,是天一觀的道長变擒。 經(jīng)常有香客問我,道長寝志,這世上最難降的妖魔是什么娇斑? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮澈段,結(jié)果婚禮上悠菜,老公的妹妹穿的比我還像新娘。我一直安慰自己败富,他們只是感情好悔醋,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著兽叮,像睡著了一般芬骄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鹦聪,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天账阻,我揣著相機(jī)與錄音,去河邊找鬼泽本。 笑死淘太,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蒲牧,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼撇贺,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了冰抢?” 一聲冷哼從身側(cè)響起松嘶,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎挎扰,沒想到半個(gè)月后翠订,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遵倦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年尽超,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骇吭。...
    茶點(diǎn)故事閱讀 38,814評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡橙弱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出燥狰,到底是詐尸還是另有隱情,我是刑警寧澤斜筐,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布龙致,位于F島的核電站,受9級特大地震影響顷链,放射性物質(zhì)發(fā)生泄漏目代。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一嗤练、第九天 我趴在偏房一處隱蔽的房頂上張望榛了。 院中可真熱鬧,春花似錦煞抬、人聲如沸霜大。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽战坤。三九已至,卻和暖如春残拐,著一層夾襖步出監(jiān)牢的瞬間途茫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工溪食, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留囊卜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像栅组,于是被迫代替她去往敵國和親雀瓢。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評論 2 351