WorkManager的基本使用

一掷匠、前言:

WorkManager 是適合用于持久性工作的推薦解決方案拧揽。如果工作始終要通過應用重啟和系統(tǒng)重新啟動來調(diào)度袍辞,便是持久性的工作扇苞。由于大多數(shù)后臺處理操作都是通過持久性工作完成的植榕,因此 WorkManager 是適用于后臺處理操作的主要推薦 API吮螺。

入門指南:

1提鸟、WorkManager 可處理三種類型的持久性工作:

  • 立即執(zhí)行:必須立即開始且很快就完成的任務宾濒,可以加急腿短。
  • 長時間運行:運行時間可能較長(有可能超過 10 分鐘)的任務。
  • 可延期執(zhí)行:延期開始并且可以定期運行的預定任務绘梦。
類型 周期 使用方式
立即 一次性 OneTimeWorkRequest 和 Worker橘忱。如需處理加急工作,請對 OneTimeWorkRequest 調(diào)用 setExpedited()卸奉。
長期運行 一次性或定期 任意 WorkRequest 或 Worker钝诚。在工作器中調(diào)用 setForeground() 來處理通知。
可延期 一次性或定期 PeriodicWorkRequest 和 Worker榄棵。

二凝颇、兼容范圍廣

WorkManager最低能兼容API Level 14,并且不需要你的設(shè)備安裝有Google Play Services疹鳄。因此拧略,你不用過于擔心兼容性問題,因為API Level 14已經(jīng)能夠兼容幾乎100%的設(shè)備了瘪弓。


image.png

WorkManager能依據(jù)設(shè)備的情況垫蛆,選擇不同的執(zhí)行方案。在API Level 23+腺怯,通過JobScheduler來完成任務袱饭,而在API Level 23以下的設(shè)備中,通過AlarmManager和Broadcast Receivers組合完成任務瓢喉。但無論采用哪種方案宁赤,任務最終都是交由Executor來完成。

WorkManager的兩個重要特點

1.針對不需要及時完成的任務

比如栓票,發(fā)送應用程序日志,同步應用程序數(shù)據(jù)愕够,備份用戶數(shù)據(jù)等走贪。站在業(yè)務的角度,這些任務都不需要立即完成惑芭,如果我們自己來管理這些任務坠狡,邏輯可能會非常復雜,若API使用不恰當遂跟,可能會消耗大量電量逃沿。

2.保證任務一定會被執(zhí)行

WorkManager能保證任務一定會被執(zhí)行婴渡,即使你的應用程序當前不在運行中,哪怕你的設(shè)備重啟凯亮,任務仍然會在適當?shù)臅r候被執(zhí)行边臼。這是因為WorkManager有自己的數(shù)據(jù)庫,關(guān)于任務的所有信息和數(shù)據(jù)都保存在這個數(shù)據(jù)庫中假消,因此柠并,只要你的任務交給了WorkManager,哪怕你的應用程序徹底退出富拗,或者設(shè)備重新啟動臼予,WorkManager依然能夠保證完成你交給的任務。

注意:WorkManager不是一種新的工作線程啃沪,它的出現(xiàn)不是為了替代其它類型的工作線程粘拾。工作線程通常立即運行,并在執(zhí)行完成后給到用戶反饋创千。而WorkManager不是即時的缰雇,它不能保證任務能立即得到執(zhí)行。

三签餐、在項目中使用WorkManager

1.在app的build.gradle中添加依賴寓涨。

dependencies {
    def work_version = "2.8.1"
    // (Java only)
    implementation "androidx.work:work-runtime:$work_version"
    // Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"
}

2.使用Worker定義任務 。

繼承Worker類氯檐,覆蓋doWork()方法戒良,所有需要在任務中執(zhí)行的代碼都在該方法中編寫。


class UploadWorker(appContext: Context, workerParams: WorkerParameters):
       Worker(appContext, workerParams) {
   override fun doWork(): Result {
       //獲取傳遞的值
       val mBookId = inputData.getString("book_id")
       val buyNum = inputData.getString("num")
       // 執(zhí)行一些后臺任務....

       //返回成功
       return Result.success()
   }
}

doWork()方法有三種類型的返回值:

  • 執(zhí)行成功返回Result.success()
  • 執(zhí)行失敗返回Result.failure()
  • 需要重新執(zhí)行返回Result.retry()

3.普通任務執(zhí)行


//傳輸數(shù)據(jù)
val inputData = Data.Builder()
     .putString("book_id", "1234")
     .putString("num", "88")
     .build()

OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadLogWorker.class)
        .setInitialDelay(10, TimeUnit.SECONDS)//延遲10秒執(zhí)行
        .setInputData(inputData) //傳輸數(shù)據(jù)
        .build();
//開始執(zhí)行任務
WorkManager.getInstance(this).enqueue(uploadWorkRequest);

設(shè)置延遲執(zhí)行任務冠摄。假設(shè)你沒有設(shè)置觸發(fā)條件糯崎,或者當你設(shè)置的觸發(fā)條件符合系統(tǒng)的執(zhí)行要求,此時河泳,系統(tǒng)有可能立刻執(zhí)行該任務沃呢,但如果你希望能夠延遲執(zhí)行,那么可以通過setInitialDelay()方法拆挥,延后任務的執(zhí)行薄霜。

4.使用WorkRequest配置任務

設(shè)置任務觸發(fā)條件。例如纸兔,我們可以設(shè)置在設(shè)備處于充電惰瓜,網(wǎng)絡(luò)已連接,且電池電量充足的狀態(tài)下汉矿,才出發(fā)我們設(shè)置的任務崎坊。

Constraints constraints = new Constraints.Builder()
        .setRequiresCharging(true)
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresBatteryNotLow(true)
        .build();
 //設(shè)置請求
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadLogWorker.class)
        .setConstraints(constraints)//設(shè)置觸發(fā)條件
        .build();
//開始執(zhí)行任務
WorkManager.getInstance(this).enqueue(uploadWorkRequest);

5.觀察任務的狀態(tài)。

任務在提交給系統(tǒng)后洲拇,通過WorkInfo獲知任務的狀態(tài)奈揍,WorkInfo包含了任務的id曲尸,tag,以及Worker對象傳遞過來的outputData男翰,以及任務當前的狀態(tài)另患。有三種方式可以得到WorkInfo對象。

WorkManager.getWorkInfosByTag()

WorkManager.getWorkInfoById()

WorkManager.getWorkInfosForUniqueWork()

如果你希望能夠?qū)崟r獲知任務的狀態(tài)奏篙。這三個方法還有對應的LiveData方法柴淘。

WorkManager.getWorkInfosByTagLiveData()

WorkManager.getWorkInfoByIdLiveData()

WorkManager.getWorkInfosForUniqueWorkLiveData()

通過LiveData,我們便可以在任務狀態(tài)發(fā)生變化的時候秘通,收到通知为严。

WorkManager.getInstance(this).getWorkInfoByIdLiveData(uploadWorkRequest.getId()).observe(MainActivity.this, new Observer<WorkInfo>()
{
    @Override
    public void onChanged(WorkInfo workInfo)
    {
        Log.d("onChanged()->", "workInfo:"+workInfo);
    }
});

6.取消任務。與觀察任務類似的肺稀,我們也可以根據(jù)Id或者Tag取消某個任務第股,或者取消所有任務。

WorkManager.getInstance(MainActivity.this).cancelAllWork();

7.WorkManager和Worker之間的參數(shù)傳遞

WorkManager通過setInputData()方法向Worker傳遞數(shù)據(jù)话原。

Data inputData = new Data.Builder()
.putString("input_data", "aaaaa")
.putString("input_data2", "hahah")
.build();

OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadLogWorker.class)
                .setInputData(inputData)
                .build();

Worker中接收數(shù)據(jù)夕吻,并在任務執(zhí)行完成后,向WorkManager傳遞數(shù)據(jù)繁仁。

@Override
public Result doWork()
{
    //接收外面?zhèn)鬟f進來的數(shù)據(jù)
    String inputData1 = getInputData().getString("input_data");
    String inputData2 = getInputData().getString("input_data2");
 
   // 任務執(zhí)行完成后返回數(shù)據(jù)
    Data outputData = new Data.Builder()
   .putString("output_data", "Task Success!")
   .build();

    return Result.success(outputData);
}

WorkManager通過LiveData的WorkInfo.getOutputData()涉馅,得到從Worker傳遞過來的數(shù)據(jù)。

WorkManager.getInstance(this).getWorkInfoByIdLiveData(uploadWorkRequest.getId()).observe(MainActivity.this, new Observer<WorkInfo>()
{
    @Override
    public void onChanged(WorkInfo workInfo)
    {
        if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED)
        {
            String outputData = workInfo.getOutputData().getString("output_data");
        }
    }
});

注意:Data只能用于傳遞一些小的基本類型數(shù)據(jù)黄虱,且數(shù)據(jù)最大不能超過10kb稚矿。

8.周期任務PeriodicWorkRequest。前面提到過捻浦,WorkRequest的兩種實現(xiàn)OneTimeWorkRequest和PeriodicWorkRequest晤揣,分別對應的是一次性任務和周期性任務。一次性任務朱灿,即任務在成功完成后昧识,便徹底結(jié)束。而周期性任務則會按照設(shè)定的時間定期執(zhí)行盗扒。二者使用起來沒有太大差別跪楞。

需要注意的是:周期性任務的間隔時間不能小于15分鐘。

PeriodicWorkRequest uploadWorkRequest = new PeriodicWorkRequest.Builder(UploadLogWorker.class, 15, TimeUnit.MINUTES)
        .setConstraints(constraints)
        .addTag(TAG)
        .build();

9.任務鏈侣灶。如果你有一系列的任務需要順序執(zhí)行习霹,那么可以利用WorkManager.beginWith().then().then()...enqueue()方法。例如:我們在上傳數(shù)據(jù)之前炫隶,需要先對數(shù)據(jù)進行壓縮。

WorkManager.getInstance(this).beginWith(compressWorkRequest).then(uploadWorkRequest).enqueue();

假設(shè)在上傳數(shù)據(jù)之前阎曹,除了壓縮數(shù)據(jù)伪阶,還需要更新本地數(shù)據(jù)煞檩。壓縮與更新本地數(shù)據(jù)二者沒有順序,但與上傳數(shù)據(jù)存在先后順序栅贴。

WorkManager.getInstance(this).beginWith(compressWorkRequest, updateLocalWorkRequest).then(uploadWorkRequest).enqueue();

假設(shè)有更復雜的任務鏈斟湃,你還可以考慮使用WorkContinuation.combine()方法,將任務鏈組合起來檐薯。

WorkContinuation workContinuation1 =  WorkManager.getInstance(this).beginWith(WorkRequestA).then(WorkRequestB);
WorkContinuation workContinuation2 =  WorkManager.getInstance(this).beginWith(WorkRequestC).then(WorkRequestD);
List<WorkContinuation> taskList = new ArrayList<>();
taskList.add(workContinuation1);
taskList.add(workContinuation2);
WorkContinuation.combine(taskList).then(WorkRequestE).enqueue();
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凝赛,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子坛缕,更是在濱河造成了極大的恐慌墓猎,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赚楚,死亡現(xiàn)場離奇詭異毙沾,居然都是意外死亡,警方通過查閱死者的電腦和手機宠页,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門左胞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人举户,你說我怎么就攤上這事烤宙。” “怎么了俭嘁?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵躺枕,是天一觀的道長。 經(jīng)常有香客問我兄淫,道長屯远,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任捕虽,我火速辦了婚禮慨丐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泄私。我一直安慰自己房揭,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布晌端。 她就那樣靜靜地躺著捅暴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咧纠。 梳的紋絲不亂的頭發(fā)上蓬痒,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音漆羔,去河邊找鬼梧奢。 笑死狱掂,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的亲轨。 我是一名探鬼主播趋惨,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼惦蚊!你這毒婦竟也來了器虾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蹦锋,失蹤者是張志新(化名)和其女友劉穎兆沙,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晕粪,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡挤悉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了巫湘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片装悲。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖尚氛,靈堂內(nèi)的尸體忽然破棺而出诀诊,到底是詐尸還是另有隱情,我是刑警寧澤阅嘶,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布属瓣,位于F島的核電站,受9級特大地震影響讯柔,放射性物質(zhì)發(fā)生泄漏抡蛙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一魂迄、第九天 我趴在偏房一處隱蔽的房頂上張望粗截。 院中可真熱鬧,春花似錦捣炬、人聲如沸熊昌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽婿屹。三九已至,卻和暖如春推溃,著一層夾襖步出監(jiān)牢的瞬間昂利,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留页眯,地道東北人梯捕。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像窝撵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子襟铭,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容