Jetpack 之 WorkManager 小白入手

?? 簡介:

??WorkManager 是一個(gè) API,它可以很合理的安排可延遲的異步任務(wù),即使應(yīng)用程序退出或者設(shè)備重新啟動(dòng),這些異步任務(wù)也有望運(yùn)行.WorkManager API是所有以前Android 后臺(tái)調(diào)度api 的合適的且推薦的替代品,包括FirebaseJobDispatcher.GcmNetworkManager,和 Job Scheduler.WorkManager 在現(xiàn)在,一致的 api 中合并了其前輩的功能,該 API 可以兼容到 API 14,同事考慮了電池的壽命.
雖然 Service也可以實(shí)現(xiàn),但是消耗電量大,而且并不允許長時(shí)間后臺(tái)執(zhí)行.PASS 掉.
特點(diǎn)

  • ?? 不需要及時(shí)完成的任務(wù).比如 發(fā)送日志,同步用戶數(shù)據(jù)等
  • ?? 保證任務(wù)一定會(huì)被執(zhí)行.即使 app不在運(yùn)行或者重啟設(shè)備.
  • ?? 兼容范圍廣.最低到API level 14.并且不需要安裝 google paly service.

?? 原理:

image.png

?? 使用方法:

先看看幾個(gè)關(guān)鍵的類.
?? Worker : 任務(wù)的執(zhí)行者,是一個(gè)抽象類,需要集成它來實(shí)現(xiàn)要執(zhí)行的任務(wù).
?? WorkRequest : 指定哪個(gè) Worker 執(zhí)行任務(wù),可以向WorkRequest中添加細(xì)節(jié),指定執(zhí)行環(huán)境,執(zhí)行順序,ID 等.WorkRequest是個(gè)抽象類,在代碼中是,使用其子類,OneTimeWorkRequest 或者PeriodicWorkRequest.
?? WorkManager :對WorkRequest進(jìn)行排隊(duì)和管理.
?? WorkStatus :包含任務(wù)的狀態(tài)和信息,以 LIiveData 的形式提供給觀察者.

1,build.gradle 添加依賴

    // Java
    implementation "androidx.work:work-runtime:2.5.0"
    // kotlin  workmanager
    implementation "androidx.work:work-runtime-ktx:2.5.0"

2,使用 Work 類定義任務(wù)

class MyWoker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {

        //耗時(shí)任務(wù)在 doWork()中執(zhí)行
        return Result.success()
    }
}

doWork() 有 3 種返回類型

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

3, 使用 WorkRequest 分配任務(wù)

??WorkRequest是一個(gè)抽象類,它有兩種實(shí)現(xiàn)方式,OneTimeWorkRequest 和 PeriodicWorkRequest,分別對應(yīng)一次性任務(wù)和周期性任務(wù).

?? 定義WorkRequest
OneTimeWorkRequest :

 var build = OneTimeWorkRequest.Builder(MyWoker::class.java).build()

PeriodicWorkRequest :

 var build = PeriodicWorkRequest.Builder(MyWoker::class.java, 15, TimeUnit.MINUTES).build()

??以下的代碼示例中,我會(huì)以O(shè)neTimeWorkRequest寫 Demo.
??PeriodicWorkRequest使用和OneTimeWorkRequest沒有太大區(qū)別,需要注意的是,間隔時(shí)間不能少于 15 分鐘.
?? 設(shè)置任務(wù)的觸發(fā)條件:
??比如,我們在設(shè)備處于充電,網(wǎng)絡(luò)連接的情況下觸發(fā)任務(wù),通過.setConstraints(constraints)方法設(shè)置觸發(fā)條件

        var constraints = Constraints.Builder()
             .setRequiresCharging(true)
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .build()

        var build = OneTimeWorkRequest.Builder(MyWoker::class.java)
            .setConstraints(constraints)
            .build()

??看下圖還有很多其他的條件,具體使用什么條件,根據(jù)需求定吧.

image.png

?? 設(shè)置任務(wù)延遲:
??通過.setInitialDelay(10,TimeUnit.SECONDS) 設(shè)置延時(shí)條件

        var build = OneTimeWorkRequest.Builder(MyWoker::class.java)
            .setConstraints(constraints)
            .setInitialDelay(10,TimeUnit.SECONDS)
            .build()

?? 設(shè)置指數(shù)退避策略:
??假如Work線程執(zhí)行異常,在 doWork()方法中返回 Result.retry(),系統(tǒng)會(huì)有默認(rèn)的的指數(shù)退避策略來重試任務(wù).也可以通過.setBackoffCriteria(BackoffPolicy.LINEAR,OneTimeWorkRequest.MIN_BACKOFF_MILLIS,TimeUnit.MINUTES)來定義指數(shù)退避策略.BackoffPolicy有兩個(gè)值LINEAR(每次重試的時(shí)間線性增加,比如第一次10分鐘,第二次就是20分鐘)、EXPONENTIAL(每次重試時(shí)間指數(shù)增加)。

        var build = OneTimeWorkRequest.Builder(MyWoker::class.java)
            .setConstraints(constraints)
            .setInitialDelay(10,TimeUnit.SECONDS)
            .setBackoffCriteria(BackoffPolicy.LINEAR,OneTimeWorkRequest.MIN_BACKOFF_MILLIS,TimeUnit.MINUTES)
            .build()

?? 為任務(wù)設(shè)置 tag 標(biāo)簽:
??設(shè)置 tag 標(biāo)簽后,可以根據(jù) tag 來跟蹤任務(wù)的狀態(tài):WorkManager.getInstance(this).getWorkInfosByTag(),也可以取消任務(wù): WorkManager.getInstance(this).cancelAllWorkByTag().

        var build = OneTimeWorkRequest.Builder(MyWoker::class.java)
            .setConstraints(constraints)
            .setInitialDelay(10,TimeUnit.SECONDS)
            .setBackoffCriteria(BackoffPolicy.LINEAR,OneTimeWorkRequest.MIN_BACKOFF_MILLIS,TimeUnit.MINUTES)
            .addTag("myTag")
            .build()

4, 將任務(wù)交給系統(tǒng),加入任務(wù)隊(duì)列

        WorkManager.getInstance(this).enqueue(build)

?? 觀察任務(wù)狀態(tài):
??觀察任務(wù)的狀態(tài)的方法如下:

image.png

??我們可以通過 LivaData 在任務(wù)狀態(tài)發(fā)生變化的的時(shí)候接收通知:

        WorkManager.getInstance(this)
            .getWorkInfosByTagLiveData("myTag")
            .observe(this,
                {
                    Log.e("TestActivity", "workInfo: $it")
                })

?? 取消任務(wù):
??取消任務(wù)的方法如下:

image.png

??與觀察任務(wù)類似,可以根據(jù) id 或者 tag 來取消某個(gè)任務(wù)或者取消所有任務(wù).

        WorkManager.getInstance(this).cancelAllWorkByTag("myTag")

5, WorkManager 和 Worker 之間的參數(shù)傳遞

??WorkManager通過setInputData()方法給 Worker 傳遞參數(shù).數(shù)據(jù)的傳遞通過 Data 對象來完成.
???? Data 只能用于傳遞一些小的數(shù)據(jù)類型,切數(shù)據(jù)不能超過 10KB.

        var inputData = Data.Builder().putString("nameS", "張三").build()
        var build = OneTimeWorkRequest.Builder(MyWoker::class.java)
            .setInputData(inputData)
             //......
            .addTag("myTag")
            .build()

??Woker 通過 getInputData()方法接受數(shù)據(jù),并在任務(wù)完成后,向 WorkManager 返回?cái)?shù)據(jù).

class MyWoker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {
        inputData.getString("nameS")?.let { Log.e("mmm", "MyWoker收到的信息: $it") }
        var outData = Data.Builder().putString("nameM", "我已經(jīng)回復(fù)張三了").build()
        return Result.success(outData)
    }
}

??WorkManager通過 LiveData 得到從 Worker 返回?cái)?shù)據(jù)

        WorkManager.getInstance(this)
            .getWorkInfosByTagLiveData("myTag")
            .observe(this, {
                for (workInfo in it) {
                    Log.d("mmm", workInfo.toString())
                    if (WorkInfo.State.SUCCEEDED.isFinished) {
                        val outputData = workInfo.outputData
                        val nameM = outputData.getString("nameM")
                        nameM?.let { it1 ->
                            Log.e("mmm", "TestActivity收到的信息: $it1")
                            WorkManager.getInstance(this@TestActivity).cancelAllWorkByTag("myTag")
                        }

                    }
                }
            })

?? 執(zhí)行結(jié)果截圖:


image.png

6, 任務(wù)鏈

?? 如果有一系列的任務(wù)需要按照順序執(zhí)行,那么可以利用WorkManager.beginWith().then().then()....enqueue()的方式構(gòu)建任務(wù).beginWith()可與傳遞單個(gè)任務(wù),也可以傳遞任務(wù)集合.

image.png

單個(gè)任務(wù):

        WorkManager.getInstance(this)
            .beginWith(build)
            .then(build)
            .then(build)
            .enqueue()

多個(gè)任務(wù):(集合)
?? WorkContinuation.combine()方法將任務(wù)鏈組合起來用

        var buildOne = WorkManager.getInstance(this)
            .beginWith(buildOne)
            .then(buildTwo)
        var buildTwo = WorkManager.getInstance(this)
            .beginWith(buildThree)
            .then(buildFour)
        var list = mutableListOf<WorkContinuation>()
        list.add(buildOne)
        list.add(buildTwo)
        WorkContinuation
            .combine(list)
            .then(buildFive)
            .enqueue()

ps:任務(wù)鏈的東西,我沒試過

END

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文主要內(nèi)容 WorkManager使用詳細(xì)介紹自定義Worker的幾種實(shí)現(xiàn)使用注意事項(xiàng) 特性 兼容Android...
    葫蘆娃大戰(zhàn)屎殼郎閱讀 2,363評論 0 1
  • 背景:通常我們在開發(fā)過程中處理后臺(tái)任務(wù)的時(shí)候可能是自己維系一個(gè)線程池或者通過一個(gè)后臺(tái)任務(wù)來完成我們的工作,然后對于...
    o螞蟻上樹o閱讀 1,869評論 0 50
  • Workmanager是jetpack系列及其重要的一部分,他可以讓用戶設(shè)定定時(shí)任務(wù),并設(shè)定一些條件,條件符合并到...
    坑逼的嚴(yán)閱讀 955評論 0 1
  • WorkManager架構(gòu)組件是用來管理后臺(tái)工作任務(wù)。這個(gè)時(shí)候你可能會(huì)奇怪了Android不是已經(jīng) 有很多管...
    tuacy閱讀 6,649評論 4 14
  • 前言 前面的內(nèi)容中我們已經(jīng)介紹了很多Jetpack中的架構(gòu)組件,可以說每一種組件的出現(xiàn)都是為了更好的解決現(xiàn)在存在的...
    rivenlee閱讀 896評論 0 1

友情鏈接更多精彩內(nèi)容