自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android進(jìn)階之后臺任務(wù)和定時服務(wù),放棄AlarmManager全面擁抱WorkManager

移動開發(fā) Android
WorkManager是google提供的異步執(zhí)行任務(wù)的管理框架,會根據(jù)手機(jī)的API版本和應(yīng)用程序的狀態(tài)來選擇適當(dāng)?shù)姆绞綀?zhí)行任務(wù)。

[[428478]]

本文轉(zhuǎn)載自微信公眾號「Android開發(fā)編程」,作者Android開發(fā)編程。轉(zhuǎn)載本文請聯(lián)系A(chǔ)ndroid開發(fā)編程公眾號。

前言

WorkManager是google提供的異步執(zhí)行任務(wù)的管理框架,會根據(jù)手機(jī)的API版本和應(yīng)用程序的狀態(tài)來選擇適當(dāng)?shù)姆绞綀?zhí)行任務(wù);

當(dāng)應(yīng)用在運(yùn)行的時候會在應(yīng)用的進(jìn)程中開一條線程來執(zhí)行任務(wù),當(dāng)退出應(yīng)用時,WorkManager會選擇根據(jù)設(shè)備的API版本使用適合的算法調(diào)用JobScheduler或者Firebase JobDispatcher,或者AlarmManager來執(zhí)行任務(wù);

今天我們來介紹下;

一、WorkManager介紹

1、什么是WorkManager

  • WorkManager 是一個 API,使您可以輕松調(diào)度那些即使在退出應(yīng)用或重啟設(shè)備時仍應(yīng)運(yùn)行的可延期異步任務(wù)。WorkManager API 是一個針對先前的 Android 后臺調(diào)度 API(包括 FirebaseJobDispatcher、GcmNetworkManager 和 JobScheduler)的合適的建議替換組件。WorkManager 在新版一致性 API 中整合了其前身的功能,該 API 支持 API 級別 14,同時可保證電池續(xù)航時間;
  • WorkManager 適用于可延期工作,即不需要立即運(yùn)行但需要可靠運(yùn)行的工作,即使用戶退出或設(shè)備重啟也不受影響。例如:向后端服務(wù)發(fā)送日志或分析數(shù)據(jù) 定期將應(yīng)用數(shù)據(jù)與服務(wù)器同步;
  • WorkManager 不適用于應(yīng)用進(jìn)程結(jié)束時能夠安全終止的運(yùn)行中后臺工作,也不適用于需要立即執(zhí)行的工作;

2、優(yōu)點(diǎn)

  • 向下兼容至api 14;
  • 可以添加任務(wù)執(zhí)行的約束條件,比如說 延遲執(zhí)行,是否在低電量模式下執(zhí)行,是否在充電模式下執(zhí)行,是否在設(shè)備空閑時執(zhí)行等等;
  • 調(diào)度一次性或周期性異步任務(wù);
  • 監(jiān)管任務(wù),可以隨時取消任務(wù);
  • 將任務(wù)鏈接起來,比如說執(zhí)行可以指定多個任務(wù)的執(zhí)行順序;
  • 確保任務(wù)執(zhí)行,即使應(yīng)用或設(shè)備重啟也同樣執(zhí)行任務(wù);

二、WorkManager使用

1、添加依賴

  1. //根據(jù)項目需要自行添加依賴,不需要全部添加 
  2.     dependencies { 
  3.       def work_version = "2.3.1" 
  4.         // (Java only
  5.         implementation "androidx.work:work-runtime:$work_version"//java 語言選這個 
  6.         // Kotlin + coroutines 
  7.         implementation "androidx.work:work-runtime-ktx:$work_version"//kotlin 選這個 
  8.       } 

2、 創(chuàng)建一個后臺任務(wù)

上傳圖片:

  1. class UploadPicWork( 
  2.     private val context: Context, 
  3.     private val workerParameters: WorkerParameters 
  4. ) : 
  5.     Worker(context, workerParameters) { 
  6.     override fun doWork(): Result { 
  7.         uploadPic()//具體上傳圖片的邏輯 
  8.         return Result.success() 
  9.     } 

2.1 創(chuàng)建一個workrequest

  1. //此處的 UploadPicWork 就是之前創(chuàng)建的任務(wù) 
  2. val uploadPicWork = OneTimeWorkRequestBuilder<UploadPicWork>() 
  3.                 .setConstraints(triggerContentMaxDelay).build() 

2.2執(zhí)行任務(wù)

  1. //此處的 uploadPicWork 就是前一步創(chuàng)建的 workrequest 
  2.   WorkManager.getInstance(myContext).enqueue(uploadPicWork) 

3、復(fù)雜的任務(wù)處理

3.1 創(chuàng)建任務(wù)執(zhí)行的約束條件

  1. //注意 以下條件都是 && 的關(guān)系 
  2. val triggerContentMaxDelay = 
  3.                 Constraints.Builder() 
  4.                 .setRequiredNetworkType(NetworkType.CONNECTED)//網(wǎng)絡(luò)鏈接的時候使用,避免各種網(wǎng)絡(luò)判斷,省時省力 
  5.                 .setRequiresDeviceIdle(false)//是否在設(shè)備空閑的時候執(zhí)行 
  6.                 .setRequiresBatteryNotLow(true)//是否在低電量的時候執(zhí)行 
  7.                 .setRequiresStorageNotLow(true)//是否在內(nèi)存不足的時候執(zhí)行 
  8.                 .setRequiresCharging(true)//是否時充電的時候執(zhí)行 
  9.                 .setTriggerContentMaxDelay(1000 * 1, TimeUnit.MILLISECONDS)//延遲執(zhí)行 
  10.                 .build() 

3.2 為任務(wù)添加約束條件

  1. val uploadPicWork = 
  2.                 OneTimeWorkRequestBuilder<UploadPicWork>() 
  3.                     .setConstraints(triggerContentMaxDelay)//約束條件 
  4.                     .build() 
  5.  WorkManager.getInstance(myContext).enqueue(uploadPicWork)//執(zhí)行 

3.3為worker 傳遞參數(shù)

  1. //可以采用這種方式傳遞參數(shù) 
  2.    val UploadPicWork = 
  3.                 OneTimeWorkRequestBuilder<UploadPicWork>() 
  4.                     //此處set input data 需要的參數(shù) 是一個Data對象,注意只可以添加一次,如果有多個參數(shù)需要傳遞,可以封裝成一個data 數(shù)據(jù)類 
  5.                     .setInputData(workDataOf("params_tag" to "params")) 
  6.                     .setConstraints(triggerContentMaxDelay).build() 

3.4 獲取參數(shù)

  1. class UploadPicWork( 
  2.     private val context: Context, 
  3.     private val workerParameters: WorkerParameters 
  4. ) : 
  5.     Worker(context, workerParameters) { 
  6.     override fun doWork(): Result { 
  7.        val params = inputData.getString("params_tag")//獲取傳遞的參數(shù) 
  8.         uploadPic()//上傳圖片 
  9.         return Result.success() 
  10.     } 

4、Worker 的狀態(tài)

在 doWork 函數(shù)中,我們返回的 Result.success(); 我們默認(rèn) ,任務(wù) uploadPic 函數(shù)順利的執(zhí)行完成了,所以返回了 success 狀態(tài),但是在實(shí)際開發(fā)過程中 可以能因?yàn)楦鞣N各樣的問題會導(dǎo)致 失敗,這時候就不能返回success了;

Worker 的各種狀態(tài)說明

  • 如果有尚未完成的前提性工作,則工作處于 BLOCKED State;
  • 如果工作能夠在滿足 約束條件 和時機(jī)條件后立即運(yùn)行,則被視為處于 ENQUEUED 狀態(tài);
  • 當(dāng) Worker 在活躍地執(zhí)行時,其處于 RUNNING State;
  • 如果 Worker 返回 Result.success(),則被視為處于 SUCCEEDED 狀態(tài)。這是一種終止 State;只有 OneTimeWorkRequest 可以進(jìn)入這種 State;
  • 如果 Worker 返回 Result.failure(),則被視為處于 FAILED 狀態(tài)。這也是一個終止 State;只有 OneTimeWorkRequest 可以進(jìn)入這種 State。所有依賴工作也會被標(biāo)記為 FAILED,并且不會運(yùn)行;
  • 當(dāng)取消尚未終止的 WorkRequest 時,它會進(jìn)入 CANCELLED State。所有依賴工作也會被標(biāo)記為 CANCELLED,并且不會運(yùn)行;

5、觀察Worker 的狀態(tài)

獲取 WorkInfo

聽過 id 獲取,可以聽過 WorkManager.getWorkInfoById(UUID) 或 WorkManager.getWorkInfoByIdLiveData(UUID) 來通過 WorkRequest id 來獲取 WorkInfo;

  1. WorkManager.getInstance(this) 
  2.                 .getWorkInfoByIdLiveData(UploadPicWork.id)// 通過id 獲取 
  3.                 .observe(this, Observer { //it:WorkInfo 
  4.                     it?.apply { 
  5.                         when (this.state) { 
  6.                             WorkInfo.State.BLOCKED -> println("BLOCKED"
  7.                             WorkInfo.State.CANCELLED -> println("CANCELLED"
  8.                             WorkInfo.State.RUNNING -> println("RUNNING"
  9.                             WorkInfo.State.ENQUEUED -> println("ENQUEUED"
  10.                             WorkInfo.State.FAILED -> println("FAILED"
  11.                             WorkInfo.State.SUCCEEDED -> println("SUCCEEDED"
  12.                             else -> println("else status ${this.state}"
  13.                         } 
  14.                     } 
  15.                 }) 

通過 tag 獲取,可以利用 WorkManager.getWorkInfosByTag(String) 或 WorkManager.getWorkInfosByTagLiveData(String) 來通過 WorkRequest 的 WorkInfo 對象;

  1. //要通過 tag 獲取,則需要先設(shè)置 tag 
  2. val UploadPicWork = 
  3.                 OneTimeWorkRequestBuilder<UploadPicWork>() 
  4.                     .setInputData(workDataOf("params_tag" to "params"))//傳遞參數(shù) 
  5.                     .setConstraints(triggerContentMaxDelay)//設(shè)置約束條件 
  6.                     .addTag("tag")//設(shè)置tag 
  7.                     .build() 
  8. //獲取 workInfo 
  9. WorkManager.getInstance(this) 
  10.                 .getWorkInfosByTagLiveData("tag"
  11.                 .observe(this, Observer {it:List<WorkInfo>//此處返回的是一個集合,作為示例代碼,默認(rèn)只取 0 index 
  12.                     it?.apply { 
  13.                         when (this[0].state) { 
  14.                             WorkInfo.State.BLOCKED -> println("BLOCKED"
  15.                             WorkInfo.State.CANCELLED -> println("CANCELLED"
  16.                             WorkInfo.State.RUNNING -> println("RUNNING"
  17.                             WorkInfo.State.ENQUEUED -> println("ENQUEUED"
  18.                             WorkInfo.State.FAILED -> println("FAILED"
  19.                             WorkInfo.State.SUCCEEDED -> println("SUCCEEDED"
  20.                             else -> println("else status ${this[0]}"
  21.                         } 
  22.                     } 
  23.                 }) 

6、多個Worker 的順序執(zhí)行

您可以使用 WorkManager 創(chuàng)建工作鏈并為其排隊。工作鏈用于指定多個關(guān)聯(lián)任務(wù)并定義這些任務(wù)的運(yùn)行順序。當(dāng)您需要以特定的順序運(yùn)行多個任務(wù)時,這尤其有用;

6.1先后順序執(zhí)行單個任務(wù)

比如說有三個任務(wù)workA,workB,workC,并且執(zhí)行順序只能時workA---->workB---->workC可以用如下的方式處理;

  1. WorkManager.getInstance() 
  2.     .beginWith(workA) 
  3.     .then(workB)  instance 
  4.     .then(workC) 
  5.     .enqueue(); 

上面的workA,workB,workC,都是WorkRequest的子類實(shí)現(xiàn)對象。WorkManager會根據(jù)上面的先后順序來執(zhí)行workA,workB,workC,,但是如果執(zhí)行過程中三個任務(wù)中有一個失敗,整個執(zhí)行都會結(jié)束。并且返回Result.failure()

6.2先后順序執(zhí)行多個任務(wù)列

有時候可能要先執(zhí)行一組任務(wù),然后再執(zhí)行下一組任務(wù),可以使用下面的方式來完成。

  1. WorkManager.getInstance() 
  2.  
  3. // First, run all the A tasks (in parallel): 
  4.  
  5. .beginWith(Arrays.asList(workA1, workA2, workA3)) 
  6.  
  7. // ...when all A tasks are finished, run the single B task: 
  8.  
  9. .then(workB) 
  10.  
  11. // ...then run the C tasks (in any order): 
  12.  
  13. .then(Arrays.asList(workC1, workC2)) 
  14.  
  15. .enqueue(); 

7、 執(zhí)行重復(fù)任務(wù)

就是在給定的時間間隔內(nèi)定期執(zhí)行任務(wù),比如說 每個一個小時,上報位置信息,每個3個小時備份一個日志等等;

這個時間間隔不可低于15分鐘;

  1. val triggerContentMaxDelay = 
  2.                 Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED) 
  3. //                    .setRequiresDeviceIdle(false
  4.                     .setRequiresBatteryNotLow(true
  5.                     .setRequiresStorageNotLow(true
  6.                     .setRequiresCharging(true
  7.                     .setTriggerContentMaxDelay(1000 * 1, TimeUnit.MILLISECONDS) 
  8.                     .build() 
  9. //            val UploadPicWork = 
  10. //                OneTimeWorkRequestBuilder<UploadPicWork>() 
  11. //                    .setInputData(workDataOf("params_tag" to "params")) 
  12. //                    .setConstraints(triggerContentMaxDelay) 
  13. //                    .addTag("tag"
  14. //                    .build() 
  15. // 
  16.             val build = PeriodicWorkRequestBuilder<UploadPicWork>( 
  17.                 1000 * 60 *15, 
  18.                 TimeUnit.MICROSECONDS 
  19.             ).setConstraints(triggerContentMaxDelay).build() 
  20.             WorkManager.getInstance(this).enqueue(build) 

8、取消任務(wù)執(zhí)行

通過任務(wù)的ID可以獲取任務(wù)從而取消任務(wù)。任務(wù)ID可以從WorkRequest中獲取;

cancelAllWork():取消所有任務(wù);

cancelAllWorkByTag(String tag):取消一組帶有相同標(biāo)簽的任務(wù);

cancelUniqueWork( String uniqueWorkName):取消唯一任務(wù);

  1. UUID compressionWorkId = compressionWork.getId(); 
  2. WorkManager.getInstance().cancelWorkById(compressionWorkId); 

注意并不是所有的任務(wù)都可以取消,當(dāng)任務(wù)正在執(zhí)行時是不能取消的,當(dāng)然任務(wù)執(zhí)行完成了,取消也是意義的,也就是說當(dāng)任務(wù)加入到ManagerWork的隊列中但是還沒有執(zhí)行時才可以取消;

9、使用WorkManager遇到的問題

9.1使用PeriodicWorkRequest只執(zhí)行一次,并不重復(fù)執(zhí)行

  1. WorkManager instance= new PeriodicWorkRequest.Builder(PollingWorker.class, 10, TimeUnit.MINUTES) 
  2.                 .build(); 

原因:PeriodicWorkRequest默認(rèn)的時間間隔是15分鐘如果設(shè)置的時間小于15分鐘,就會出現(xiàn)問題;

解決方法:設(shè)置的默認(rèn)時間必須大于或等于15分鐘。另外要注意,就算設(shè)置的時間為15分鐘也不一定間隔15分鐘就執(zhí)行;

9.2在doWork()方法中更新UI導(dǎo)致崩潰

原因:doWork()方法是在WorkManager管理的后臺線程中執(zhí)行的,更新UI操作只能在主線程中進(jìn)行

總結(jié)

 

在這個物欲橫流人心浮躁的社會,我們一起學(xué)習(xí)加油共勉

 

責(zé)任編輯:武曉燕 來源: Android開發(fā)編程
相關(guān)推薦

2023-12-01 08:21:51

開發(fā)者Android組件庫

2023-11-25 09:30:13

Android后臺任務(wù)

2023-11-27 19:32:25

Android

2018-09-12 21:25:15

iOSAppcrash

2012-12-31 13:36:28

Android開發(fā)Alarmmanage

2021-10-14 14:32:27

AndroidActiviAPI

2022-01-10 09:05:32

Linux后臺命令

2009-06-19 20:38:49

Linux操作系統(tǒng)

2021-02-06 06:10:44

ifconfigip 命令系統(tǒng)運(yùn)維

2023-04-26 11:59:06

Swift異步編程

2024-02-26 08:00:00

MergeRebase開發(fā)

2011-10-14 09:27:57

Hadoop數(shù)據(jù)庫SQL Server

2011-10-14 16:03:30

微軟Hadoop

2010-02-22 13:01:54

HTML 5谷歌

2015-11-23 17:14:04

eBayKubernetesOpenStack

2022-06-30 11:36:10

KubeSphereGitOpsLinux

2013-12-02 09:44:33

RadwareOpenStack

2019-05-09 15:53:27

PythonR數(shù)據(jù)科學(xué)

2011-12-13 20:36:26

Android

2021-10-03 15:08:32

Android
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號