jetpack之workManager官方文档解析
基礎介紹
workmanager是一個可延期的后臺異步任務,可以用來取代以前的android后臺調度任務
通俗的講就是可以用來做后臺異步任務,那他有什么優勢呢,和以前的后臺api方法相比有什么區別呢?
帶著這倆個問題開始往下看
兼容性
首先workmanager兼容性很好,包括 FirebaseJobDispatcher、GcmNetworkManager 和 JobScheduler
都可以替換成workmanager,同時支持 API 級別 14,對電量續航也做了優化(省電)
基礎功能
創建方式:通過單例創建workmanager,enqueue方法將任務加入隊列
val myWorkRequest = ... WorkManager.getInstance(myContext).enqueue(myWorkRequest)任務(workrequest)是抽象基類,有倆個子類
OneTimeWorkRequest和PeriodicWorkRequest
OneTimeWorkRequest 適用于調度非重復性工作,而 PeriodicWorkRequest 則更適合調度以一定間隔重復執行的工作。
一次性工作:
val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)如果是復雜一點的一次性工作可以用構建器,可以在這里對你的任務添加一些策略
val uploadWorkRequest: WorkRequest =OneTimeWorkRequestBuilder<MyWork>()// Additional configuration.build()定期性工作
val saveRequest =PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)// Additional configuration.build() //工作的運行時間間隔定為一小時。 //可以定義的最短重復間隔是 15 分鐘request由work類組成。work類就是具體執行流程的類
如下TestWork類繼承Workr類,實現doWork方法,在里面上傳圖片
class TestWorker(appContext: Context, workerParams: WorkerParameters):Worker(appContext, workerParams) {override fun doWork(): Result {// Do the work here--in this case, upload the images.uploadImages()// Indicate whether the work finished successfully with the Resultreturn Result.success()} } 從 doWork() 返回的 Result 會通知 WorkManager 服務工作是否成功,以及工作失敗時是否應重試工作。 Result.success():工作成功完成。 Result.failure():工作失敗。 Result.retry():工作失敗,應根據其重試政策在其他時間嘗試。到這里,一個簡單的workmanager就介紹完了,包括workmanager的創建方式,request的組成,work的創建
接下來是workmanger的一些配置
約束
可以給任務添加約束(比如在wifi條件下才運行,在充電狀態下才運行)
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.UNMETERED).setRequiresCharging(true).build()val myWorkRequest: WorkRequest =OneTimeWorkRequestBuilder<MyWork>().setConstraints(constraints).build() //可以添加的約束類型如下延遲工作
下面的示例為延遲10分鐘
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>().setInitialDelay(10, TimeUnit.MINUTES).build()調度
對于一組完整的異步任務,可以運行一次,也可以重復運行,對每一組任務進行命名,用來單獨操作他們
//給一個單獨的work添加標識 val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>().addTag("cleanup").build() //可以通過WorkManager.cancelAllWorkByTag(String)取消任務 //可以通過WorkManager.getWorkInfosByTag(String)獲取這個任務,得到一個WorkInfo對象 //可以通過workManager.getWorkInfosByTagLiveData(String)得到一個livedata,當這個對象的tag的work執行完成之后,這個livedata會觸發靈活的重試機制
LINEAR和EXPONENTIAL倆種策略
當你在work的dowork方法中返回Result.retry()的時候,會進行重試機制
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>().setBackoffCriteria(BackoffPolicy.LINEAR,OneTimeWorkRequest.MIN_BACKOFF_MILLIS,TimeUnit.MILLISECONDS).build() //MIN_BACKOFF_MILLIS為10秒 //LINEAR策略,每次嘗試重試的時候,重試間隔都會增加10秒,20,30,40類推 //如果是EXPONENTIAL策略,那么重試時長是20、40、80 秒,以此類推。work中的數據傳遞
// Define the Worker requiring input class UploadWork(appContext: Context, workerParams: WorkerParameters): Worker(appContext, workerParams) {override fun doWork(): Result {val imageUriInput =inputData.getString("IMAGE_URI") ?: return Result.failure()uploadFile(imageUriInput)return Result.success()}... }// Create a WorkRequest for your Worker and sending it input val myUploadWork = OneTimeWorkRequestBuilder<UploadWork>().setInputData(workDataOf("IMAGE_URI" to "http://...")).build()//還可以通過 Result.success(outputData)將數據傳遞給下一個work工作狀態
一次性工作狀態
對于 one-time 工作請求,工作的初始狀態為 ENQUEUED。
在 ENQUEUED 狀態下,您的工作會在滿足其 Constraints 和初始延遲計時要求后立即運行。接下來,該工作會轉為 RUNNING 狀態,然后可能會根據工作的結果轉為 SUCCEEDED、FAILED 狀態;或者,如果結果是 retry,它可能會回到 ENQUEUED 狀態。在此過程中,隨時都可以取消工作,取消后工作將進入 CANCELLED 狀態。
SUCCEEDED、FAILED 和 CANCELLED 均表示此工作的終止狀態。如果您的工作處于上述任何狀態,WorkInfo.State.isFinished() 都將返回 true。
定期工作的狀態
成功和失敗狀態僅適用于一次性工作和鏈式工作。定期工作只有一個終止狀態 CANCELLED。這是因為定期工作永遠不會結束。每次運行后,無論結果如何,系統都會重新對其進行調度。圖 2 描述了定期工作的精簡狀態圖。
唯一工作
確保在某一個時刻只有一個相同的實例存在
- [WorkManager.enqueueUniqueWork()](https://developer.android.google.cn/reference/androidx/work/WorkManager#enqueueUniqueWork(java.lang.String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest))(用于一次性工作)
- [WorkManager.enqueueUniquePeriodicWork()](https://developer.android.google.cn/reference/androidx/work/WorkManager#enqueueUniquePeriodicWork(java.lang.String, androidx.work.ExistingPeriodicWorkPolicy, androidx.work.PeriodicWorkRequest))(用于定期工作)
這兩種方法都接受 3 個參數:
- uniqueWorkName - 用于唯一標識工作請求的 String。
- existingWorkPolicy - 此 enum 可告知 WorkManager 如果已有使用該名稱且尚未完成的唯一工作鏈,應執行什么操作。如需了解詳情,請參閱沖突解決政策。
- work - 要調度的 WorkRequest。
上述代碼在 sendLogs 作業已處于隊列中的情況下運行,系統會保留現有的作業,并且不會添加新的作業
ExistingPeriodicWorkPolicy有三種選項
-
REPLACE:用新工作替換現有工作。此選項將取消現有工作。
-
KEEP:保留現有工作,并忽略新工作。
-
APPEND:將新工作附加到現有工作的末尾。此政策將導致您的新工作鏈接到現有工作,在現有工作完成后運行。
-
APPEND_OR_REPLACE 功能類似于 APPEND,不過它并不依賴于先決條件工作狀態。即使現有工作變為 CANCELLED 或 FAILED 狀態,新工作仍會運行。
狀態監聽
可以通過三種方式獲取查詢work
// by id workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>// by name workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>// by tag workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>該查詢會返回 WorkInfo 對象的 ListenableFuture,該值包含工作的 id、其標記、其當前的 State 以及通過 Result.success(outputData) 設置的任何輸出數據
下面的代碼展示了,當syncWorker完成后,顯示一個消息
workManager.getWorkInfoByIdLiveData(syncWorker.id).observe(viewLifecycleOwner) { workInfo ->if(workInfo?.state == WorkInfo.State.SUCCEEDED) {Snackbar.make(requireView(),R.string.work_completed, Snackbar.LENGTH_SHORT).show()} }復雜的work狀態查詢
以下示例說明了如何查找帶有“syncTag”標記、處于 FAILED 或 CANCELLED 狀態,且唯一工作名稱為“preProcess”或“sync”的所有工作。
val workQuery = WorkQuery.Builder.fromTags(listOf("syncTag")).addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)).addUniqueWorkNames(listOf("preProcess", "sync")).build()val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery) WorkQuery` 中的每個組件(標記、狀態或名稱)與其他組件都是 `AND` 邏輯關系。組件中的每個值都是 `OR` 邏輯關系。例如:`(name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)WorkQuery 也適用于等效的 LiveData 方法 getWorkInfosLiveData()
取消和停止工作
// by id workManager.cancelWorkById(syncWorker.id)// by name workManager.cancelUniqueWork("sync")// by tag workManager.cancelAllWorkByTag("syncTag")觀察進度
在work的dowork方法中通過
setProgress(firstUpdate)//設置進度觀察進度
WorkManager.getInstance(applicationContext)// requestId is the WorkRequest id.getWorkInfoByIdLiveData(requestId).observe(observer, Observer { workInfo: WorkInfo? ->if (workInfo != null) {val progress = workInfo.progressval value = progress.getInt(Progress, 0)// Do something with progress information}})鏈接工作
您可以使用 WorkManager 創建工作鏈并將其加入隊列。工作鏈用于指定多個依存任務并定義這些任務的運行順序。當您需要以特定順序運行多個任務時,此功能尤其有用。
如需創建工作鏈,您可以使用 WorkManager.beginWith(OneTimeWorkRequest) 或 WorkManager.beginWith(List),這會返回 WorkContinuation 實例。
然后,可以使用 WorkContinuation 通過 then(OneTimeWorkRequest) 或 then(List) 添加依存 OneTimeWorkRequest。 .
每次調用 WorkContinuation.then(...) 都會返回一個新的 WorkContinuation 實例。如果添加了 OneTimeWorkRequest 實例的 List,這些請求可能會并行運行。
最后,您可以使用 WorkContinuation.enqueue() 方法對 WorkContinuation 工作鏈執行 enqueue() 操作。
下面我們來看一個示例。在本例中,有 3 個不同的工作器作業配置為運行(可能并行運行)。然后這些工作器的結果將聯接起來,并傳遞給正在緩存的工作器作業。最后,該作業的輸出將傳遞到上傳工作器,由上傳工作器將結果上傳到遠程服務器。
WorkManager.getInstance(myContext)// Candidates to run in parallel.beginWith(listOf(plantName1, plantName2, plantName3))// Dependent work (only runs after all previous work in chain).then(cache).then(upload)// Call enqueue to kick things off.enqueue()如果想將plantName1, plantName2, plantName3work的輸出作為下一個work cache的輸入。那么就需要用到輸入合并器
WorkManager 提供兩種不同類型的 InputMerger:
- OverwritingInputMerger 會嘗試將所有輸入中的所有鍵添加到輸出中。如果發生沖突,它會覆蓋先前設置的鍵。
- ArrayCreatingInputMerger 會嘗試合并輸入,并在必要時創建數組。
也可以創建 InputMerger 的子類來編寫自己的用例。
by the last最后說一下
請注意,Worker.doWork() 是同步調用 - 您將會以阻塞方式完成整個后臺工作,并在方法退出時完成工作。如果您在 doWork() 中調用異步 API 并返回 Result,則回調可能無法正常運行。如果您遇到這種情況,請考慮使用 ListenableWorker(請參閱在 ListenableWorker 中進行線程處理)。
總結
以上是生活随笔為你收集整理的jetpack之workManager官方文档解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 个人任务5,事后诸葛亮任务
- 下一篇: 3个工具助你玩转正则表达式