天天看點

如何使用WorkManager執行背景任務(下)

0x00 WorkManager的進階用法

在上一文中已經了解到

WorkManager

的基本用法之後,今天來看看它的一些進階用法:

  • 鍊式任務調用
  • 唯一任務序列
  • 傳遞參數和擷取傳回值

0x01 鍊式任務(Chained tasks)

WorkManager

在執行多個工作任務的時候,可以指定執行順序。假設一個應用程式中有3個

OneTimeWorkRequest

對象:

workA

workB

workC

。這幾個任務需要按照順序執行,那麼可以使用

WorkManager.beginWith()

方法加入

workA

,這時候會傳回一個

WorkContinuation

對象,它定義了工作任務的執行序列。然後通過它再調用

WorkContinuation.then()

workB

workC

加入到執行隊列中,最後執行

WorkManager.enqueue()

方法。

WorkManager.getInstance()
    .beginWith(workA)
        // Note: WorkManager.beginWith() returns a
        // WorkContinuation object; the following calls are
        // to WorkContinuation methods
    .then(workB)    // FYI, then() returns a new WorkContinuation instance
    .then(workC)
    .enqueue()
      

  

WorkManager

會按照指定的順序來執行

workA

workB

workC

。如果其中有一個工作任務執行的時候傳回

Worker.Result.FAILURE

,那麼整個執行序列就會停止。

WorkManager.beginWith()

方法可以傳遞多個

Worker

對象,表示可以并行執行的任務組,然後再調用

then()

方法。當這并行任務組都執行完之後才會執行接下來

then

中的工作任務。

WorkManager.getInstance()
    // 首先,并行執行workA1,workA2,workA3這三個任務
    .beginWith(workA1, workA2, workA3)
    // 當三個任務都完成之後, 開始執行workB:
    .then(workB)
    // 最後再并行執行 workC1,workC2
    .then(workC1, workC2)
    .enqueue()
      

還可以通過

WorkContinuation.combine()

方法建立更加複雜的連結任務調用序列。它可以将兩個

WorkContinuation

對象合并,假設要調用如下的任務序列:

val chain1 = WorkManager.getInstance()
    .beginWith(workA)
    .then(workB)
val chain2 = WorkManager.getInstance()
    .beginWith(workC)
    .then(workD)
val chain3 = WorkContinuation
    .combine(chain1, chain2)
    .then(workE)
chain3.enqueue()
      

這個鍊式執行順序是:子鍊 A->B 與子鍊 C->D 并行執行的,

workA

執行後再執行

workB

,以及

workC

執行後執行

workD

;然後等待

workB

以及

workD

都執行完,最後執行

workE

需要注意的是,

WorkManager

無法保證兩個子鍊的執行順序,有可能

chain1

chain2

快,也有可能是

chain1

chain2

慢。

0x02 唯一任務序列(Unique work sequences)

在應用程式開發中,可能會多次把同一個鍊式任務添加到

WorkManager

中,但希望隻有一個鍊式任務在執行,這時候可以使用唯一任務序列對鍊式任務指定處理規則。假設,做一個下載下傳檔案操作,對一個檔案下載下傳連結,我們不需要重複下載下傳,隻需要添加一次,後面再添加這個任務,就忽略掉,因為我們不希望重複多次下載下傳同一個檔案。是以當添加兩個同樣名稱為"download"操作任務時,對于唯一任務序列來說,可以通過

ExistingWorkPolicy

中的

REPLACE

KEEP

APPEND

,來指定添加的政策。

  • REPLACE:新任務将替換舊的
  • KEEP:新任務會被丢棄,舊的任務會被保持
  • APPEND:追加,舊任務執行之後再執行新的任務。

使用

beginUniqueWork()

方法可以建立任務序列,并且可以指定唯一的一個名稱(name)。然後再

ExistingWorkPolicy

指定任務的替換政策

WorkContinuation continuation = mWorkManager
                .beginUniqueWork("download",
                       ExistingWorkPolicy.KEEP,
                       OneTimeWorkRequest.from(CleanupWorker))
      

0x03 傳遞參數和擷取傳回值

任務執行可以傳遞參數以及擷取到任務執行的結果。使用

WorkRequst.Builder.setInputData()

方法傳遞一個

Data

對象,它是key-value形式的對象,使用

Data.Builder

來建立。在

Worker

類中可以使用

Worker.getInputData()

擷取到參數。

同樣地,在

Worker

中可以使用

Worker.setOutputData()

設定一個

Data

對象的傳回值。要擷取到這個傳回值就通過

LiveData<WorkStatus>

舉個栗子:

有一個下載下傳任務,在

Worker

中擷取傳遞過來的參數url,然後執行下載下傳,最後設定下載下傳結果。

// the result key:
const val KEY_RESULT = "result"
class DownloadWorker(context : Context, params : WorkerParameters) : Worker(context, params)  {
    override fun doWork(): Result {
        // 擷取參數
        val url = getInputData("url")
        // 執行下載下傳
        val result = download(url);
        // 設定下載下傳結果
        val output: Data = mapOf(KEY_RESULT to result).toWorkData()
        setOutputData(output)
        // 任務執行成功
        return Result.SUCCESS
    }
}
      

然後,通過

WorkRequest

傳遞參數

// 構造下載下傳連結參數
val urlData: Data = mapOf("url" to "https://developer.android.com/images/topic/libraries/architecture/workmanager-chain.svg")
                     .toWorkData()
// 構造WorkRequest并傳遞下載下傳參數
val downloadWork = OneTimeWorkRequest.Builder<DownloadWorker>()
        .setInputData(urlData)
        .build()
// 交給WorkManager執行任務
WorkManager.getInstance().enqueue(downloadWork)
      

最後,通過

WorkStatus

擷取傳回值

WorkManager.getInstance().getStatusById(downloadWork.id)
        .observe(this, Observer { status ->
            if (status != null && status.state.isFinished) {
                val myResult = status.outputData.getString(KEY_RESULT,
                      myDefaultValue)
                // ... do something with the result ...
            }
        })      

0x04 引用

https://developer.android.com/topic/libraries/architecture/workmanager/advanced

https://developer.android.com/reference/androidx/work/ExistingWorkPolicy

http://clmirror.storage.googleapis.com/codelabs/android-workmanager/index.html?index=..%2F..%2Findex#0