Android Jetpack架構(gòu)組件(六)— WorkManager

一拆内、WorkManager簡介

WorkManager是適合用于持久性工作的推薦解決方案顽爹。
持久性的工作:如果工作始終要通過應(yīng)用重啟和系統(tǒng)重新啟動來調(diào)度到逊,便是持久性的工作泉手。
由于大多數(shù)后臺處理操作都是通過持久性工作完成的黔寇,因此 WorkManager 是適用于后臺處理操作的主要推薦 API。

持久性工作的類型:

WorkManager 可處理三種類型的持久性工作:

  • 立即執(zhí)行:必須立即開始且很快就完成的任務(wù)斩萌,可以加急缝裤。
  • 長時間運行:運行時間可能較長(有可能超過 10 分鐘)的任務(wù)。
  • 可延期執(zhí)行:延期開始并且可以定期運行的預(yù)定任務(wù)颊郎。


    持久性工作類型
類型 周期 使用方式
立即 一次性 OneTimeWorkRequest 和 Worker憋飞。如需處理加急工作,請對 OneTimeWorkRequest 調(diào)用 setExpedited()姆吭。
長期運行 一次性或定期 任意 WorkRequest 或 Worker榛做。在工作器中調(diào)用 setForeground() 來處理通知。
可延期 一次性或定期 PeriodicWorkRequest 和 Worker内狸。
WorkManager 適用于:
  • 主要用用于后臺運行的操作检眯;
  • 用于延遲運行并且再應(yīng)用退出或設(shè)備重啟必須能夠可靠運行的任務(wù)。

Android為后臺任務(wù)提供了多種解決方案答倡,如JobScheduler轰传,Loader驴党,Service等瘪撇。如果這些API沒有被適當?shù)厥褂茫赡軙拇罅康碾娏俊?/p>

Service也是用于后臺運行港庄,為什么不用Service倔既?
原因:Google自O(shè)reo(API 26) 開始,對后臺service服務(wù)做了一些個限制鹏氧,如在不被允許創(chuàng)建后臺服務(wù)的情況下渤涌,調(diào)用了startService()方法,會導(dǎo)致IllegalStateException異常把还。因此如果要繼續(xù)使用service就必須通過Context類得靜態(tài)方法startForegroundService()來啟動前臺服務(wù)实蓬,系統(tǒng)也創(chuàng)建了服務(wù),這就導(dǎo)致了應(yīng)用得在5秒鐘之內(nèi)調(diào)用該服務(wù)的 startForeground() 方法使其位于前臺被用戶發(fā)現(xiàn)吊履,要是超過了5s那App就拋ANR(Application Not Response)安皱。

1、WorkManager兼容性

WorkManager最低能兼容API Level 14艇炎,幾乎兼容100%Android設(shè)備酌伊。
WorkManager能依據(jù)設(shè)備的情況,選擇不同的執(zhí)行方案缀踪。在API Level 23+居砖,通過JobScheduler來完成任務(wù)虹脯,而在API Level 23以下的設(shè)備中,通過AlarmManager和Broadcast Receivers組合完成任務(wù)奏候。但無論采用哪種方案循集,任務(wù)最終都是交由Executor來完成。

2蔗草、WorkManager特點

1.針對不需要及時完成的任務(wù)

比如暇榴,發(fā)送應(yīng)用程序日志,同步應(yīng)用程序數(shù)據(jù)蕉世,備份用戶數(shù)據(jù)等蔼紧。站在業(yè)務(wù)的角度,這些任務(wù)都不需要立即完成狠轻,如果我們自己來管理這些任務(wù)奸例,邏輯可能會非常復(fù)雜,若API使用不恰當向楼,可能會消耗大量電量查吊。

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

WorkManager能保證任務(wù)一定會被執(zhí)行,即使你的應(yīng)用程序當前不在運行中湖蜕,哪怕你的設(shè)備重啟逻卖,任務(wù)仍然會在適當?shù)臅r候被執(zhí)行。這是因為WorkManager有自己的數(shù)據(jù)庫昭抒,關(guān)于任務(wù)的所有信息和數(shù)據(jù)都保存在這個數(shù)據(jù)庫中评也,因此,只要你的任務(wù)交給了WorkManager灭返,哪怕你的應(yīng)用程序徹底退出盗迟,或者設(shè)備重新啟動,WorkManager依然能夠保證完成你交給的任務(wù)熙含。

注意:WorkManager不是一種新的工作線程罚缕,它的出現(xiàn)不是為了替代其它類型的工作線程。工作線程通常立即運行怎静,并在執(zhí)行完成后給到用戶反饋邮弹。而WorkManager不是即時的,它不能保證任務(wù)能立即得到執(zhí)行蚓聘。

二腌乡、WorkManager使用

1、首先三個重要的類

  1. Worker
    我們要執(zhí)行的具體任務(wù)或粮。需要繼承Worker,重寫doWork方法导饲,然后在里面寫具體的邏輯。
  2. WorkRequest
    上面的Worker是定義了我們要在后臺的任務(wù),而這個類是對Worker的包裝渣锦。
    下面兩個都是繼承了WorkRequest:
    OneTimeWorkRequest: 只執(zhí)行一次的任務(wù)
    PeriodicWorkRequest: 重復(fù)執(zhí)行的任務(wù)(重復(fù)間隔大于15分鐘)
  3. WorkManager
    是對WorkRequest的管理類硝岗。

2、在app的build.gradle中添加依賴

dependencies {
    def work_version = "2.7.1"

    // (Java only)
    implementation "androidx.work:work-runtime:$work_version"

    // Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"

    // optional - RxJava2 support
    implementation "androidx.work:work-rxjava2:$work_version"

    // optional - GCMNetworkManager support
    implementation "androidx.work:work-gcm:$work_version"

    // optional - Test helpers
    androidTestImplementation "androidx.work:work-testing:$work_version"

    // optional - Multiprocess support
    implementation "androidx.work:work-multiprocess:$work_version"
}

3袋毙、創(chuàng)建自定義Worker任務(wù)

class MyWorker extends Worker {

    private WorkerParameters workerParameters;

    public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
        workerParameters = workerParams;
    }

    @NonNull
    @Override
    public Result doWork() {
        Log.e("MyWorker", "doWork()");
        //從外面?zhèn)鬟M來的值
        String value = workerParameters.getInputData().getString("key");
        //處理數(shù)據(jù)后創(chuàng)建data
        Data data = new Data.Builder().putString("key", value).build();
        return Result.success(data);
    }
}

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

  • 執(zhí)行成功返回Result.success()型檀,可攜帶參數(shù)
  • 執(zhí)行失敗返回Result.failure(),可攜帶參數(shù)
  • 需要重新執(zhí)行返回Result.retry()

4听盖、使用WorkRequest配置任務(wù)并把請求添加到請求隊列

通過WorkRequest配置我們的任務(wù)何時運行以及如何運行胀溺。

      //1、創(chuàng)建傳遞給Work的參數(shù)
      Data sendData = new Data.Builder().putString("key", "來自Activity的數(shù)據(jù)").build();
      //2皆看、初始化請求對象request仓坞,并添加自定義Worker
      OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(MyWorker.class).setInputData(sendData).build();
      //3、添加回調(diào)更新
      WorkManager.getInstance(activity).getWorkInfoByIdLiveData(oneTimeWorkRequest.getId()).observe(activity, new Observer<WorkInfo>() {
         @Override
         public void onChanged(WorkInfo workInfo) {
            //注意這個方法會回調(diào)多次腰吟,要加這個判斷
            if(workInfo.getState().isFinished()){
               //執(zhí)行完成的處理无埃,接受worker返回的結(jié)果
               //這里的key與MyWorker的key需要一致
               String result = workInfo.getOutputData().getString("key");
            }
         }
      });


      //4、添加到任務(wù)隊列
      WorkManager.getInstance(activity).enqueue(oneTimeWorkRequest);

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

三、WorkManager其他使用方式

1灵疮、WorkRequest兩個子類
  • OneTimeWorkRequest:執(zhí)行一次性任務(wù)
  • PeriodicWorkRequest:執(zhí)行周期性任務(wù)
2织阅、WorkRequest可設(shè)置任務(wù)觸發(fā)條件

以下皆使用OneTimeWorkRequest,OneTimeWorkRequest和PeriodicWorkRequest使用方式相同震捣。

      //1荔棉、創(chuàng)建條件:在設(shè)備處于充電,網(wǎng)絡(luò)已連接伍派,且電池電量充足的狀態(tài)下江耀,才觸發(fā)我們設(shè)置的任務(wù)剩胁。
      Constraints constraints = new Constraints.Builder()
              //在設(shè)備處于充電
              .setRequiresCharging(true)
              //網(wǎng)絡(luò)已連接
              .setRequiredNetworkType(NetworkType.CONNECTED)
              //電池電量充足的狀態(tài)下
              .setRequiresBatteryNotLow(true)
              //充電中
              .setRequiresCharging(true)
              //cpu空閑時
              .setRequiresDeviceIdle(true)
              //可用存儲是否不低于最小值
              .setRequiresStorageNotLow(true)
              .build();

      //2诉植、設(shè)置條件
      OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
              .setInputData(sendData)
              .setConstraints(constraints)
              .build();
3、設(shè)置延遲執(zhí)行任務(wù)

假設(shè)你沒有設(shè)置觸發(fā)條件昵观,或者當你設(shè)置的觸發(fā)條件符合系統(tǒng)的執(zhí)行要求晾腔,此時,系統(tǒng)有可能立刻執(zhí)行該任務(wù)啊犬,但如果你希望能夠延遲執(zhí)行灼擂,那么可以通過setInitialDelay()方法,延后任務(wù)的執(zhí)行觉至。


OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
              //設(shè)置傳入Worker數(shù)據(jù)
              .setInputData(sendData)
              //設(shè)置觸發(fā)條件
              .setConstraints(constraints)
              //設(shè)置符合觸發(fā)條件后剔应,延遲10秒執(zhí)行
              .setInitialDelay(10, TimeUnit.SECONDS)
              //設(shè)置指數(shù)退避策略
              .setBackoffCriteria(BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS)//設(shè)置指數(shù)退避算法
              //設(shè)置標簽
              .addTag("UploadTag")
              .build();
4、設(shè)置指數(shù)退避策略

假如Worker線程的執(zhí)行出現(xiàn)了異常,比如服務(wù)器宕機峻贮,那么你可能希望過一段時間席怪,重試該任務(wù)。那么你可以在Worker的doWork()方法中返回Result.retry()纤控,系統(tǒng)會有默認的指數(shù)退避策略來幫你重試任務(wù)挂捻,你也可以通過setBackoffCriteria()方法,自定義指數(shù)退避策略船万。

OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
              //設(shè)置傳入Worker數(shù)據(jù)
              .setInputData(sendData)
              //設(shè)置觸發(fā)條件
              .setConstraints(constraints)
              //設(shè)置符合觸發(fā)條件后刻撒,延遲10秒執(zhí)行
              .setInitialDelay(10, TimeUnit.SECONDS)
              //設(shè)置指數(shù)退避策略
              .setBackoffCriteria(BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS)//設(shè)置指數(shù)退避算法
              //設(shè)置標簽
              .addTag("UploadTag")
              .build();
5、為任務(wù)設(shè)置Tag標簽

設(shè)置Tag后耿导,你就可以通過該抱歉跟蹤任務(wù)的狀態(tài)WorkManager.getWorkInfosByTagLiveData(String tag)或者取消任務(wù)WorkManager.cancelAllWorkByTag(String tag)声怔。

OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
              //設(shè)置傳入Worker數(shù)據(jù)
              .setInputData(sendData)
              //設(shè)置觸發(fā)條件
              .setConstraints(constraints)
              //設(shè)置符合觸發(fā)條件后,延遲10秒執(zhí)行
              .setInitialDelay(10, TimeUnit.SECONDS)
              //設(shè)置指數(shù)退避策略
              .setBackoffCriteria(BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS)//設(shè)置指數(shù)退避算法
              //設(shè)置標簽
              .addTag("UploadTag")
              .build();
6舱呻、將任務(wù)提交給系統(tǒng)捧搞。

WorkManager.enqueue()方法會將你配置好的WorkRequest交給系統(tǒng)來執(zhí)行。

      WorkManager.getInstance(activity).enqueue(oneTimeWorkRequest);
7狮荔、觀察任務(wù)的狀態(tài)

任務(wù)在提交給系統(tǒng)后胎撇,通過WorkInfo獲知任務(wù)的狀態(tài),WorkInfo包含了任務(wù)的id殖氏,tag晚树,以及Worker對象傳遞過來的outputData,以及任務(wù)當前的狀態(tài)雅采。有三種方式可以得到WorkInfo對象爵憎。

WorkManager.getWorkInfosByTag()

WorkManager.getWorkInfoById()

WorkManager.getWorkInfosForUniqueWork()

如果你希望能夠?qū)崟r獲知任務(wù)的狀態(tài)。這三個方法還有對應(yīng)的LiveData方法婚瓜。

WorkManager.getWorkInfosByTagLiveData()

WorkManager.getWorkInfoByIdLiveData()

WorkManager.getWorkInfosForUniqueWorkLiveData()

通過觀察LiveData宝鼓,我們便可以在任務(wù)狀態(tài)發(fā)生變化的時候,收到通知巴刻。

WorkManager.getInstance(activity).getWorkInfoByIdLiveData(oneTimeWorkRequest.getId()).observe(activity, new Observer<WorkInfo>() {
         @Override
         public void onChanged(WorkInfo workInfo) {
            //注意這個方法會回調(diào)多次愚铡,要加這個判斷
            if(workInfo.getState().isFinished()){
               //執(zhí)行完成的處理,接受worker返回的結(jié)果
               //這里的key與MyWorker的key需要一致
               String result = workInfo.getOutputData().getString("key");
            }
         }
      });
8胡陪、取消任務(wù)

與觀察任務(wù)類似的沥寥,我們也可以根據(jù)Id或者Tag取消某個任務(wù),或者取消所有任務(wù)柠座。

      WorkManager.getInstance(activity).cancelWorkById(UUID)
      WorkManager.getInstance(activity).cancelAllWorkByTag("")
      WorkManager.getInstance(activity).cancelAllWork();
9邑雅、周期任務(wù)PeriodicWorkRequest

一次性任務(wù),即任務(wù)在成功完成后妈经,便徹底結(jié)束淮野。而周期性任務(wù)則會按照設(shè)定的時間定期執(zhí)行捧书。

注意:周期性任務(wù)的間隔時間不能小于15分鐘。源碼設(shè)置最小15分鐘骤星。

PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(MyWorker.class, 15, TimeUnit.MINUTES)
              .setConstraints(constraints)
              .build();
10鳄厌、任務(wù)鏈

如果你有一系列的任務(wù)需要順序執(zhí)行,那么可以利用WorkManager.beginWith().then().then().enqueue()方法;
例如:我們在上傳圖片之前妈踊,需要先對圖片進行壓縮了嚎,還需要更新本地圖片。壓縮與更新本地圖片二者沒有順序廊营,但與上傳圖片存在先后順序歪泳。

WorkManager.getInstance(this).beginWith(compressWorkRequest, updateLocalWorkRequest).then(uploadWorkRequest).enqueue();
11、WorkContinuation復(fù)雜任務(wù)鏈

執(zhí)行順序:
任務(wù)鏈一:A—>B
任務(wù)鏈二:C—>D
任務(wù)鏈一—>任務(wù)鏈二—>E

WorkContinuation workContinuation1 =  WorkManager.getInstance(activity).beginWith(WorkRequestA).then(WorkRequestB);
      WorkContinuation workContinuation2 =  WorkManager.getInstance(activity).beginWith(WorkRequestC).then(WorkRequestD);
      List<WorkContinuation> taskList = new ArrayList<>();
      taskList.add(workContinuation1);
      taskList.add(workContinuation2);
      WorkContinuation.combine(taskList).then(WorkRequestE).enqueue();

四露筒、Kotlin中使用

1呐伞、CoroutineWorker 中的線程處理

對于 Kotlin 用戶,WorkManager 為協(xié)程提供了一流的支持慎式。如要開始使用伶氢,請將 work-runtime-ktx 包含到您的 gradle 文件中。不要擴展 Worker瘪吏,而應(yīng)擴展 CoroutineWorker癣防,后者包含 doWork() 的掛起版本。例如掌眠,如果要構(gòu)建一個簡單的 CoroutineWorker 來執(zhí)行某些網(wǎng)絡(luò)操作蕾盯,您需要執(zhí)行以下操作:

class CoroutineDownloadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        val data = downloadSynchronously("https://www.google.com")
        saveData(data)
        return Result.success()
    }
}

請注意,CoroutineWorker.doWork() 是一個“掛起”函數(shù)蓝丙。此代碼不同于 Worker级遭,不會在 Configuration 中指定的 Executor 中運行,而是默認為 Dispatchers.Default渺尘。您可以提供自己的 CoroutineContext 來自定義這個行為挫鸽。在上面的示例中,您可能希望在 Dispatchers.IO 上完成此操作鸥跟,如下所示:

class CoroutineDownloadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        withContext(Dispatchers.IO) {
            val data = downloadSynchronously("https://www.google.com")
            saveData(data)
            return Result.success()
        }
    }
}

CoroutineWorker 通過取消協(xié)程并傳播取消信號來自動處理停工情況丢郊。您無需執(zhí)行任何特殊操作來處理停工情況

2锌雀、在其他進程中運行 CoroutineWorker

您還可以使用 RemoteCoroutineWorkerListenableWorker 的實現(xiàn))將工作器綁定到特定進程蚂夕。

RemoteCoroutineWorker 會使用您在構(gòu)建工作請求時于輸入數(shù)據(jù)中提供的兩個額外參數(shù)綁定到特定進程:ARGUMENT_CLASS_NAMEARGUMENT_PACKAGE_NAME

以下示例演示了如何構(gòu)建綁定到特定進程的工作請求:

val PACKAGE_NAME = "com.example.background.multiprocess"

val serviceName = RemoteWorkerService::class.java.name
val componentName = ComponentName(PACKAGE_NAME, serviceName)

val data: Data = Data.Builder()
   .putString(ARGUMENT_PACKAGE_NAME, componentName.packageName)
   .putString(ARGUMENT_CLASS_NAME, componentName.className)
   .build()

return OneTimeWorkRequest.Builder(ExampleRemoteCoroutineWorker::class.java)
   .setInputData(data)
   .build()

對于每個 RemoteWorkerService腋逆,您還需要在 AndroidManifest.xml 文件中添加服務(wù)定義:

<manifest ... >
    <service
            android:name="androidx.work.multiprocess.RemoteWorkerService"
            android:exported="false"
            android:process=":worker1" />

        <service
            android:name=".RemoteWorkerService2"
            android:exported="false"
            android:process=":worker2" />
    ...
</manifest>

3、RxWorker 中的線程處理

我們在 WorkManager 與 RxJava 之間提供互操作性侈贷。如需開始使用這種互操作性惩歉,除了在您的 gradle 文件中包含 work-runtime 之外等脂,還應(yīng)包含 work-rxjava3 依賴項。而且還有一個支持 rxjava2 的 work-rxjava2 依賴項撑蚌,您可以根據(jù)情況使用上遥。

然后,您應(yīng)該擴展 RxWorker争涌,而不是擴展 Worker粉楚。最后替換 RxWorker.createWork() 方法以返回 Single<Result>,用于表示代碼執(zhí)行的 Result亮垫,如下所示:

class RxDownloadWorker(
        context: Context,
        params: WorkerParameters
) : RxWorker(context, params) {
    override fun createWork(): Single<Result> {
        return Observable.range(0, 100)
                .flatMap { download("https://www.example.com") }
                .toList()
                .map { Result.success() }
    }
}

請注意模软,RxWorker.createWork() 在主線程上調(diào)用,但默認情況下會在后臺線程上訂閱返回值饮潦。您可以替換 RxWorker.getBackgroundScheduler() 來更改訂閱線程燃异。

RxWorkeronStopped() 時,系統(tǒng)會處理訂閱继蜡,因此您無需以任何特殊方式處理停工情況回俐。

4、ListenableWorker 中的線程處理

在某些情況下稀并,您可能需要提供自定義線程處理策略仅颇。例如,您可能需要處理基于回調(diào)的異步操作碘举。在這種情況下灵莲,不能只依靠 Worker 來完成操作,因為它無法以阻塞方式完成這項工作殴俱。WorkManager 通過 ListenableWorker 支持該用例政冻。ListenableWorker 是最基本的工作器 API;Worker线欲、CoroutineWorkerRxWorker 都是從這個類衍生而來的明场。ListenableWorker 只會發(fā)出信號以表明應(yīng)該開始和停止工作,而線程處理則完全交您決定李丰。開始工作信號在主線程上調(diào)用苦锨,因此請務(wù)必手動轉(zhuǎn)到您選擇的后臺線程。

抽象方法 ListenableWorker.startWork() 會返回一個將使用操作的 Result 設(shè)置的 ListenableFuture趴泌。ListenableFuture 是一個輕量級接口:它是一個 Future舟舒,用于提供附加監(jiān)聽器和傳播異常的功能。在 startWork 方法中嗜憔,應(yīng)該返回 ListenableFuture秃励,完成操作后,您需要使用操作的 Result 設(shè)置這個返回結(jié)果吉捶。您可以通過以下兩種方式之一創(chuàng)建 ListenableFuture 實例:

  1. 如果您使用的是 Guava夺鲜,請使用 ListeningExecutorService皆尔。
  2. 否則,請將 councurrent-futures 包含到您的 gradle 文件中并使用 CallbackToFutureAdapter币励。

如果您希望基于異步回調(diào)執(zhí)行某些工作慷蠕,則應(yīng)以類似如下的方式執(zhí)行:

class CallbackWorker(
        context: Context,
        params: WorkerParameters
) : ListenableWorker(context, params) {
    override fun startWork(): ListenableFuture<Result> {
        return CallbackToFutureAdapter.getFuture { completer ->
            val callback = object : Callback {
                var successes = 0

                override fun onFailure(call: Call, e: IOException) {
                    completer.setException(e)
                }

                override fun onResponse(call: Call, response: Response) {
                    successes++
                    if (successes == 100) {
                        completer.set(Result.success())
                    }
                }
            }

            repeat(100) {
                downloadAsynchronously("https://example.com", callback)
            }

            callback
        }
    }
}

如果您的工作停止會發(fā)生什么?如果預(yù)計工作會停止食呻,則始終會取消 ListenableWorkerListenableFuture流炕。通過使用 CallbackToFutureAdapter,您只需添加一個取消監(jiān)聽器即可仅胞,如下所示:

class CallbackWorker(
        context: Context,
        params: WorkerParameters
) : ListenableWorker(context, params) {
    override fun startWork(): ListenableFuture<Result> {
        return CallbackToFutureAdapter.getFuture { completer ->
            val callback = object : Callback {
                var successes = 0

                override fun onFailure(call: Call, e: IOException) {
                    completer.setException(e)
                }

                override fun onResponse(call: Call, response: Response) {
                    ++successes
                    if (successes == 100) {
                        completer.set(Result.success())
                    }
                }
            }

 completer.addCancellationListener(cancelDownloadsRunnable, executor)

            repeat(100) {
                downloadAsynchronously("https://example.com", callback)
            }

            callback
        }
    }
}
在其他進程中運行 ListenableWorker

您還可以使用 RemoteListenableWorkerListenableWorker 的實現(xiàn))將工作器綁定到特定進程每辟。

RemoteListenableWorker 會使用您在構(gòu)建工作請求時于輸入數(shù)據(jù)中提供的兩個額外參數(shù)綁定到特定進程:ARGUMENT_CLASS_NAMEARGUMENT_PACKAGE_NAME

以下示例演示了如何構(gòu)建綁定到特定進程的工作請求:

val PACKAGE_NAME = "com.example.background.multiprocess"

val serviceName = RemoteWorkerService::class.java.name
val componentName = ComponentName(PACKAGE_NAME, serviceName)

val data: Data = Data.Builder()
   .putString(ARGUMENT_PACKAGE_NAME, componentName.packageName)
   .putString(ARGUMENT_CLASS_NAME, componentName.className)
   .build()

return OneTimeWorkRequest.Builder(ExampleRemoteListenableWorker::class.java)
   .setInputData(data)
   .build()

對于每個 RemoteWorkerService饼问,您還需要在 AndroidManifest.xml 文件中添加服務(wù)定義:

<manifest ... >
    <service
            android:name="androidx.work.multiprocess.RemoteWorkerService"
            android:exported="false"
            android:process=":worker1" />

        <service
            android:name=".RemoteWorkerService2"
            android:exported="false"
            android:process=":worker2" />
    ...
</manifest>

五影兽、總結(jié)

1、WorkManager作用處理后臺任務(wù)莱革。出于設(shè)備電量的考慮峻堰,為開發(fā)者提供了WorkManager,旨在將一些不需要及時完成的任務(wù)交給它來完成盅视。
2捐名、WorkManager會根據(jù)系統(tǒng)的版本,使用不同的策略來完成任務(wù)闹击,有可能因為版本原因無法正常使用镶蹋。
3、周期任務(wù):Android認為Success和Failure都屬于終止類的通知赏半,可能使用LiveData觀察周期任務(wù)時不會收到Success這類的通知贺归。

參考:Android開發(fā)者網(wǎng)站W(wǎng)orkManager使用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市断箫,隨后出現(xiàn)的幾起案子拂酣,更是在濱河造成了極大的恐慌,老刑警劉巖仲义,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婶熬,死亡現(xiàn)場離奇詭異,居然都是意外死亡埃撵,警方通過查閱死者的電腦和手機赵颅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來暂刘,“玉大人饺谬,你說我怎么就攤上這事≡Ч撸” “怎么了商蕴?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵叠萍,是天一觀的道長芝发。 經(jīng)常有香客問我绪商,道長,這世上最難降的妖魔是什么辅鲸? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任格郁,我火速辦了婚禮,結(jié)果婚禮上独悴,老公的妹妹穿的比我還像新娘例书。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著惕鼓,像睡著了一般敢艰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锉罐,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音,去河邊找鬼晒喷。 笑死,一個胖子當著我的面吹牛访敌,可吹牛的內(nèi)容都是我干的凉敲。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼寺旺,長吁一口氣:“原來是場噩夢啊……” “哼爷抓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起阻塑,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤蓝撇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后叮姑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唉地,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年传透,在試婚紗的時候發(fā)現(xiàn)自己被綠了耘沼。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡朱盐,死狀恐怖群嗤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情兵琳,我是刑警寧澤狂秘,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布骇径,位于F島的核電站,受9級特大地震影響者春,放射性物質(zhì)發(fā)生泄漏破衔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一钱烟、第九天 我趴在偏房一處隱蔽的房頂上張望晰筛。 院中可真熱鬧,春花似錦拴袭、人聲如沸读第。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怜瞒。三九已至,卻和暖如春般哼,著一層夾襖步出監(jiān)牢的瞬間吴汪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工逝她, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留浇坐,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓黔宛,卻偏偏與公主長得像近刘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子臀晃,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

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