使用 Kotlin API 實踐 WorkManager

WorkManager 提供了一系列 API 能夠更加便捷地規劃異步任務,即便在應用被關閉以後或者設備重啓以後,仍然須要保證當即執行的或者推遲執行的任務被正常處理。對於 Kotlin 開發者,WorkManager 爲協程提供了最佳的支持。在本文中,我將經過實踐 WorkManager codelab 爲你們展現 WorkManager 中與協程相關的基本操做。那麼讓咱們開始吧!android

WorkManager 基礎

當您須要某個任務保持運行狀態,即便用戶切換到別的界面或者用戶將應用切換到後臺,甚至設備重啓的時候仍然不影響任務狀態,那麼很是推薦使用 WorkManager。相似的應用場景包括:git

  • 上傳日誌或者報告數據
  • 使用濾鏡處理圖片的同時保存圖片
  • 經過網絡按期同步本地數據

若是您的即時任務能夠在用戶脫離某個做用域時結束,好比切換到其它界面,咱們建議您仍是直接使用 Kotlin 協程。github

在這個 WorkManager codelab 教程中,咱們會對圖片進行模糊化處理,而且將處理後的數據存儲在磁盤上。咱們看一下這個過程當中須要哪些操做。數據庫

添加 work-runtime-ktx 依賴:網絡

// 獲取最新的版本號  https://developer.android.google.cn/jetpack/androidx/releases/work
def work_version = "2.5.0"
implementation "androidx.work:work-runtime-ktx:$work_version"

首先實現咱們本身的 Worker 類。咱們會在這裏實現真正須要在後臺執行業務的代碼。您能夠擴展 Worker 類,而且複寫 doWork() 方法。因爲這個類很是重要,咱們會在後邊內容中進行詳細介紹。這裏是它最初的實現代碼。app

/* Copyright 2020 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 */

class BlurWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {

    override fun doWork(): Result {
        val resourceUri = inputData.getString(KEY_IMAGE_URI)

        return try {
            if (resourceUri.isNullOrEmpty()) {
                Timber.e("Invalid input uri")
                throw IllegalArgumentException("Invalid input uri")
            }

            val outputData = blurAndWriteImageToFile(resourceUri)
            Result.success(outputData)
        } catch (throwable: Throwable) {
            Timber.e(throwable, "Error applying blur")
            Result.failure()
        }
    }
…
}

接下來,建立咱們的 work 請求,在本例中,咱們但願整個操做僅運行一次,因此咱們使用 OneTimeWorkRequest.Builder,將須要模糊化處理的圖片的 Uri 做爲參數傳入。異步

Kotlin 小貼士 : 要建立輸入數據,咱們能夠使用 workDataOf 函數,它會幫咱們建立數據構建器,而且填充鍵值對,而後爲咱們建立數據。ide

/* Copyright 2020 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 */

val blurBuilder = OneTimeWorkRequestBuilder<BlurWorker>()
val data = workDataOf(KEY_IMAGE_URI to imageUri.toString())
blurBuilder.setInputData(data)

咱們使用 WorkManager 類將上面所作的工做添加到計劃隊列而且運行。咱們能夠提供須要執行的任務和這些任務的限制條件。函數

/* Copyright 2020 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 */

val workManager = WorkManager.getInstance(application)
val continuation = workManager.beginUniqueWork(blurBuilder.build())
// 執行任務
continuation.enqueue()

使 Worker 開始執行任務

當您使用 Worker 的時候,WorkManager 會在後臺線程中自動調用 Worker.doWork()。doWork() 返回的 Result 會告知 WorkManager 服務是否成功,若是失敗則告知是否須要重試。ui

Worker.doWork() 屬於同步調用 -- 您的後臺操做須要以阻塞的方式執行,而且全部任務須要在整個 doWork() 函數結束的時候完成。若是您在 doWork() 裏調用異步的 API 而後返回結果,那麼您回調函數的執行可能會出現問題。

可是若是我但願進行異步操做怎麼辦?

咱們來將上面的示例操做變得複雜一點,好比我但願在數據庫中存儲全部進行模糊化處理的文件的 Uri。

因此我建立了:

  • 一個簡單的 BlurredImage 實體
  • 一個用於插入和獲取圖片的 DAO 類
  • 數據庫

相關的實現代碼請 點擊這裏

若是您須要執行異步操做,好比在數據庫中存儲數據或者發起網絡請求,在 Kotlin 中,咱們推薦使用 CoroutineWorker

CoroutineWorker 經過使用 Kotlin 協程來執行異步任務。

doWork() 方法是一個 suspend 方法。也就是說咱們這裏能夠調用可掛起的 dao 函數。

/* Copyright 2020 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 */

class BlurWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {

    override suspend fun doWork(): Result {
        val resourceUri = inputData.getString(KEY_IMAGE_URI)

        return try {
            if (resourceUri.isNullOrEmpty()) {
                Timber.e("Invalid input uri")
                throw IllegalArgumentException("Invalid input uri")
            }

            val outputData = blurAndWriteImageToFile(resourceUri)
            // 將 uri 存儲到數據庫
           val imageDao = ImagesDatabase.getDatabase(applicationContext).blurredImageDao()
            imageDao.insert(BlurredImage(resourceUri))

            Result.success(outputData)
        } catch (throwable: Throwable) {
            Timber.e(throwable, "Error applying blur")
            Result.failure()
        }
    }
...
}

doWork() 默認使用 Dispatchers.Default。您能夠將其替換爲您所需的 Dispatcher。在這裏,咱們不須要這麼作,由於 Room 已經將數據插入操做放在另外的 Dispatcher 中完成了。更多相關內容能夠參考 Room Kotlin API。

開始使用 CoroutineWorker 來執行異步任務吧,即便用戶關閉應用也能夠確保任務完成。

若是您但願瞭解更多關於 WorkManager 的內容,請關注將來的相關文章。在那以前,能夠訪問咱們的 codelab 和文檔:

相關文章
相關標籤/搜索