Jetpack WorkManager的使用-完全解析
谷歌官方API介紹
兼容范圍廣
Pangu-Immortal (Pangu-Immortal) · GitHub
WorkManager最低能兼容API Level 14,并且不需要你的設備安裝有Google Play Services。因此,你不用過于擔心兼容性問題,因為API Level 14已經能夠兼容幾乎100%的設備了。
WorkManager依據設備情況選擇方案
WorkManager能依據設備的情況,選擇不同的執行方案。在API Level 23+,通過JobScheduler來完成任務,而在API Level 23以下的設備中,通過AlarmManager和Broadcast Receivers組合完成任務。但無論采用哪種方案,任務最終都是交由Executor來完成。
源代碼:https://github.com/yugu88/Jetpack-demos
WorkManager的兩個重要特點
1.針對不需要及時完成的任務
比如,發送應用程序日志,同步應用程序數據,備份用戶數據等。站在業務的角度,這些任務都不需要立即完成,如果我們自己來管理這些任務,邏輯可能會非常復雜,若API使用不恰當,可能會消耗大量電量。
2.保證任務一定會被執行
WorkManager能保證任務一定會被執行,即使你的應用程序當前不在運行中,哪怕你的設備重啟,任務仍然會在適當的時候被執行。這是因為WorkManager有自己的數據庫,關于任務的所有信息和數據都保存在這個數據庫中,因此,只要你的任務交給了WorkManager,哪怕你的應用程序徹底退出,或者設備重新啟動,WorkManager依然能夠保證完成你交給的任務。
注意:WorkManager不是一種新的工作線程,它的出現不是為了替代其它類型的工作線程。工作線程通常立即運行,并在執行完成后給到用戶反饋。而WorkManager不是即時的,它不能保證任務能立即得到執行。在項目中使用WorkManager
1.在app的build.gradle中添加依賴。
dependencies {def versions = "2.2.0"implementation "androidx.work:work-runtime:$versions" }2.使用Worker定義任務 。
繼承Worker類,覆蓋doWork()方法,所有需要在任務中執行的代碼都在該方法中編寫。
public class UploadLogWorker extends Worker {public UploadLogWorker(@NonNull Context context, @NonNull WorkerParameters workerParams){super(context, workerParams);}/*** 耗時的任務,在doWork()方法中執行* */@NonNull@Overridepublic Result doWork(){Log.e("UploadLogWorker", "doWork()");return Result.success();} }doWork()方法有三種類型的返回值:
- 執行成功返回Result.success()
- 執行失敗返回Result.failure()
- 需要重新執行返回Result.retry()
3.使用WorkRequest配置任務。通過WorkRequest配置我們的任務何時運行以及如何運行。
- 設置任務觸發條件。例如,我們可以設置在設備處于充電,網絡已連接,且電池電量充足的狀態下,才出發我們設置的任務。
- 將該Constraints設置到WorkRequest。WorkRequest是一個抽象類,它有兩種實現,OneTimeWorkRequest和PeriodicWorkRequest,分別對應的是一次性任務和周期性任務。
- 設置延遲執行任務。假設你沒有設置觸發條件,或者當你設置的觸發條件符合系統的執行要求,此時,系統有可能立刻執行該任務,但如果你希望能夠延遲執行,那么可以通過setInitialDelay()方法,延后任務的執行。
- 設置指數退避策略。假如Worker線程的執行出現了異常,比如服務器宕機,那么你可能希望過一段時間,重試該任務。那么你可以在Worker的doWork()方法中返回Result.retry(),系統會有默認的指數退避策略來幫你重試任務,你也可以通過setBackoffCriteria()方法,自定義指數退避策略。
- 為任務設置Tag標簽。設置Tag后,你就可以通過該抱歉跟蹤任務的狀態WorkManager.getWorkInfosByTagLiveData(String tag)或者取消任務WorkManager.cancelAllWorkByTag(String tag)。
4.將任務提交給系統。WorkManager.enqueue()方法會將你配置好的WorkRequest交給系統來執行。
WorkManager.getInstance(this).enqueue(uploadWorkRequest);5.觀察任務的狀態。
任務在提交給系統后,通過WorkInfo獲知任務的狀態,WorkInfo包含了任務的id,tag,以及Worker對象傳遞過來的outputData,以及任務當前的狀態。有三種方式可以得到WorkInfo對象。
WorkManager.getWorkInfosByTag()
WorkManager.getWorkInfoById()
WorkManager.getWorkInfosForUniqueWork()
如果你希望能夠實時獲知任務的狀態。這三個方法還有對應的LiveData方法。
WorkManager.getWorkInfosByTagLiveData()
WorkManager.getWorkInfoByIdLiveData()
WorkManager.getWorkInfosForUniqueWorkLiveData()
通過LiveData,我們便可以在任務狀態發生變化的時候,收到通知。
WorkManager.getInstance(this).getWorkInfoByIdLiveData(uploadWorkRequest.getId()).observe(MainActivity.this, new Observer<WorkInfo>() {@Overridepublic void onChanged(WorkInfo workInfo){Log.d("onChanged()->", "workInfo:"+workInfo);} });6.取消任務。與觀察任務類似的,我們也可以根據Id或者Tag取消某個任務,或者取消所有任務。
WorkManager.getInstance(MainActivity.this).cancelAllWork();7.WorkManager和Worker之間的參數傳遞。數據的傳遞通過Data對象來完成。
WorkManager通過setInputData()方法向Worker傳遞數據。
Data inputData = new Data.Builder().putString("input_data", "Hello World!").build();OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadLogWorker.class).setInputData(inputData).build();Worker中接收數據,并在任務執行完成后,向WorkManager傳遞數據。
@Override public Result doWork() {//接收外面傳遞進來的數據String inputData = getInputData().getString("input_data");// 任務執行完成后返回數據Data outputData = new Data.Builder().putString("output_data", "Task Success!").build();return Result.success(outputData); }WorkManager通過LiveData的WorkInfo.getOutputData(),得到從Worker傳遞過來的數據。
WorkManager.getInstance(this).getWorkInfoByIdLiveData(uploadWorkRequest.getId()).observe(MainActivity.this, new Observer<WorkInfo>() {@Overridepublic void onChanged(WorkInfo workInfo){if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED){String outputData = workInfo.getOutputData().getString("output_data");}} }); 注意:Data只能用于傳遞一些小的基本類型數據,且數據最大不能超過10kb。8.周期任務PeriodicWorkRequest。前面提到過,WorkRequest的兩種實現OneTimeWorkRequest和PeriodicWorkRequest,分別對應的是一次性任務和周期性任務。一次性任務,即任務在成功完成后,便徹底結束。而周期性任務則會按照設定的時間定期執行。二者使用起來沒有太大差別。
需要注意的是:周期性任務的間隔時間不能小于15分鐘。
PeriodicWorkRequest uploadWorkRequest = new PeriodicWorkRequest.Builder(UploadLogWorker.class, 15, TimeUnit.MINUTES).setConstraints(constraints).addTag(TAG).build();9.任務鏈。如果你有一系列的任務需要順序執行,那么可以利用WorkManager.beginWith().then().then()...enqueue()方法。例如:我們在上傳數據之前,需要先對數據進行壓縮。
WorkManager.getInstance(this).beginWith(compressWorkRequest).then(uploadWorkRequest).enqueue();假設在上傳數據之前,除了壓縮數據,還需要更新本地數據。壓縮與更新本地數據二者沒有順序,但與上傳數據存在先后順序。
WorkManager.getInstance(this).beginWith(compressWorkRequest, updateLocalWorkRequest).then(uploadWorkRequest).enqueue();假設有更復雜的任務鏈,你還可以考慮使用WorkContinuation.combine()方法,將任務鏈組合起來。
WorkContinuation workContinuation1 = WorkManager.getInstance(this).beginWith(WorkRequestA).then(WorkRequestB); WorkContinuation workContinuation2 = WorkManager.getInstance(this).beginWith(WorkRequestC).then(WorkRequestD); List<WorkContinuation> taskList = new ArrayList<>(); taskList.add(workContinuation1); taskList.add(workContinuation2); WorkContinuation.combine(taskList).then(WorkRequestE).enqueue();采用WorkContinuation.combine()的任務鏈執行順序
源代碼:https://github.com/Pangu-Immortal/Jetpack-demos
總結
開發者經常需要處理后臺任務,如果處理后臺任務所采用的API沒有被正確使用,那么很可能會消耗大量設備的電量。Android出于設備電量的考慮,為開發者提供了WorkManager,旨在將一些不需要及時完成的任務交給它來完成。雖然WorkManager宣稱,能夠保證任務得到執行,但我在真實設備中,發現應用程序徹底退出與重啟設備,任務都沒有再次執行。查閱了相關資料,發現這應該與系統有關系。我們前面也提到了,WorkManager會根據系統的版本,決定采用JobScheduler或是AlarmManager+Broadcast Receivers來完成任務。但是這些API很可能會受到OEM系統的影響。比如,假設某個系統不允許AlarmManager自動喚起,那么WorkManager很可能就無法正常使用。
而后我在模擬器中進行測試,模擬器采用的是Google原生系統,發現無論是徹底退出應用程序,或是重啟設備,任務都能夠被執行。所以,WorkManager在真實設備中不能正常使用,很可能就是系統的問題。因此,開發者在使用WorkManager作為解決方案時,一定要慎重。
另外,我還發現,周期任務的實際執行,與所設定的時間差別較大。執行時間看起來并沒有太明顯的規律。并且在任務執行完成后,WorkInfo并不會收到Success的通知。查閱了相關資料,發現Android認為Success和Failure都屬于終止類的通知。意思是,如果發出這類通知,則表明任務徹底結束,而周期任務不會徹底終止,會一直執行下去,所以我們在使用LiveData觀察周期任務時,不會收到Success這類的通知。這也是我們需要注意的地方。
總結
以上是生活随笔為你收集整理的Jetpack WorkManager的使用-完全解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Coil - Google推荐的协程图片
- 下一篇: Jetpack CameraX 最新最全