WorkManager 提供了一系列 API 能夠更加便捷地規劃異步任務,即便在應用被關閉以後或者設備重啓以後,仍然須要保證當即執行的或者推遲執行的任務被正常處理。對於 Kotlin 開發者,WorkManager 爲協程提供了最佳的支持。在本文中,我將經過實踐 WorkManager codelab 爲你們展現 WorkManager 中與協程相關的基本操做。那麼讓咱們開始吧!android
當您須要某個任務保持運行狀態,即便用戶切換到別的界面或者用戶將應用切換到後臺,甚至設備重啓的時候仍然不影響任務狀態,那麼很是推薦使用 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 的時候,WorkManager 會在後臺線程中自動調用 Worker.doWork()。doWork() 返回的 Result 會告知 WorkManager 服務是否成功,若是失敗則告知是否須要重試。ui
Worker.doWork()
屬於同步調用 -- 您的後臺操做須要以阻塞的方式執行,而且全部任務須要在整個 doWork() 函數結束的時候完成。若是您在 doWork() 裏調用異步的 API 而後返回結果,那麼您回調函數的執行可能會出現問題。
咱們來將上面的示例操做變得複雜一點,好比我但願在數據庫中存儲全部進行模糊化處理的文件的 Uri。
因此我建立了:
相關的實現代碼請 點擊這裏。
若是您須要執行異步操做,好比在數據庫中存儲數據或者發起網絡請求,在 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 和文檔: