最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android?Jetpack庫(kù)重要組件WorkManager的使用

 更新時(shí)間:2022年08月10日 15:59:03   作者:Android技術(shù)棧  
WorkManager是Android?Jetpack的一個(gè)強(qiáng)大的組件,用于處理后臺(tái)耗時(shí)任務(wù)。后臺(tái)任務(wù)可以是一次性的,也可以是重復(fù)的,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

WorkManager是Jetpack很重要的一個(gè)組件; 本篇我們就先來(lái)講講它是如何使用的,在講解之前我們先了解關(guān)于后臺(tái)處理的一些痛點(diǎn)

后臺(tái)處理指南

我們知道每個(gè) Android 應(yīng)用都有一個(gè)主線(xiàn)程,它負(fù)責(zé)處理界面(包括測(cè)量和繪制視圖)、協(xié)調(diào)用戶(hù)互動(dòng)以及接收生命周期事件; 如果有太多工作在主線(xiàn)程中進(jìn)行,則應(yīng)用可能會(huì)掛起或運(yùn)行速度變慢,從而導(dǎo)致用戶(hù)體驗(yàn)不佳。任何長(zhǎng)時(shí)間運(yùn)行的計(jì)算和操作(例如解碼位圖、訪(fǎng)問(wèn)磁盤(pán)或執(zhí)行網(wǎng)絡(luò)請(qǐng)求)都應(yīng)在單獨(dú)的后臺(tái)線(xiàn)程上完成

一般來(lái)說(shuō),任何所需時(shí)間超過(guò)幾毫秒的任務(wù)都應(yīng)該分派到后臺(tái)線(xiàn)程; 在用戶(hù)與應(yīng)用積極互動(dòng)時(shí),可能需要執(zhí)行幾項(xiàng)這樣的任務(wù);即使在用戶(hù)沒(méi)有積極使用應(yīng)用時(shí),應(yīng)用可能也需要運(yùn)行一些任務(wù)(例如,定期與后端服務(wù)器同步或定期從應(yīng)用內(nèi)提取新內(nèi)容)

后臺(tái)處理面臨的挑戰(zhàn)

后臺(tái)任務(wù)會(huì)使用設(shè)備的有限資源,例如 RAM 和電池電量; 如果處理不當(dāng),可能會(huì)導(dǎo)致用戶(hù)體驗(yàn)不佳;為了最大限度地延長(zhǎng)電池續(xù)航時(shí)間并強(qiáng)制推行良好的應(yīng)用行為,Android 會(huì)在應(yīng)用(或前臺(tái)服務(wù)通知)對(duì)用戶(hù)不可見(jiàn)時(shí),限制后臺(tái)工作;為此Google在不同平臺(tái)上逐步的改進(jìn)

Android 6.0(API 級(jí)別 23)引入了低電耗模式和應(yīng)用待機(jī)模式

低電耗模式會(huì)在未插接設(shè)備的電源,在屏幕關(guān)閉的情況下,讓設(shè)備在一段時(shí)間內(nèi)保持不活動(dòng)狀態(tài),那么設(shè)備就會(huì)進(jìn)入低電耗模式; 在低電耗模式下,系統(tǒng)會(huì)嘗試通過(guò)限制應(yīng)用訪(fǎng)問(wèn)占用大量網(wǎng)絡(luò)和 CPU 資源的服務(wù)來(lái)節(jié)省電量。它還會(huì)阻止應(yīng)用訪(fǎng)問(wèn)網(wǎng)絡(luò),并延遲其作業(yè)、同步和標(biāo)準(zhǔn)鬧鐘

系統(tǒng)會(huì)定期退出低電耗模式一小段時(shí)間,讓?xiě)?yīng)用完成其延遲的活動(dòng); 在此維護(hù)期內(nèi),系統(tǒng)會(huì)運(yùn)行所有待處理的同步、作業(yè)和鬧鐘,并允許應(yīng)用訪(fǎng)問(wèn)網(wǎng)絡(luò)。在每個(gè)維護(hù)期結(jié)束時(shí),系統(tǒng)會(huì)再次進(jìn)入低電耗模式,暫停網(wǎng)絡(luò)訪(fǎng)問(wèn)并推遲作業(yè)、同步和鬧鐘

隨著時(shí)間的推移,系統(tǒng)安排維護(hù)期的次數(shù)越來(lái)越少,這有助于在設(shè)備未連接至充電器的情況下長(zhǎng)期處于不活動(dòng)狀態(tài)時(shí)降低耗電量; 一旦用戶(hù)通過(guò)移動(dòng)設(shè)備、打開(kāi)屏幕或連接至充電器喚醒設(shè)備,系統(tǒng)就會(huì)立即退出低電耗模式,并且所有應(yīng)用都會(huì)恢復(fù)正?;顒?dòng)

應(yīng)用待機(jī)模式允許系統(tǒng)判定應(yīng)用在用戶(hù)未主動(dòng)使用它時(shí)是否處于閑置狀態(tài); 當(dāng)用戶(hù)有一段時(shí)間未觸摸應(yīng)用時(shí),系統(tǒng)便會(huì)作出此判定;當(dāng)用戶(hù)將設(shè)備插入電源時(shí),系統(tǒng)會(huì)從待機(jī)狀態(tài)釋放應(yīng)用,允許它們自由訪(fǎng)問(wèn)網(wǎng)絡(luò)并執(zhí)行任何待處理的作業(yè)和同步。如果設(shè)備長(zhǎng)時(shí)間處于閑置狀態(tài),系統(tǒng)將允許閑置應(yīng)用訪(fǎng)問(wèn)網(wǎng)絡(luò),頻率大約每天一次

低電耗模式和應(yīng)用待機(jī)模式管理在 Android 6.0 或更高版本上運(yùn)行的所有應(yīng)用的行為,無(wú)論它們是否專(zhuān)用于 API 級(jí)別 23

Android 7.0(API 級(jí)別 24)限制了隱式廣播

引入了隨時(shí)隨地使用低電耗模式; 使得低電耗模式又前進(jìn)了一步,隨時(shí)隨地可以省電;只要屏幕關(guān)閉了一段時(shí)間,且設(shè)備未插入電源,低電耗模式就會(huì)對(duì)應(yīng)用使用熟悉的 CPU 和網(wǎng)絡(luò)限制;這意味著用戶(hù)即使將設(shè)備放入口袋里也可以省電

Android 8.0(API 級(jí)別 26)進(jìn)一步限制后臺(tái)行為

例如在后臺(tái)獲取位置信息和釋放緩存的喚醒鎖定

Android 9.0(API 級(jí)別 28)引入了應(yīng)用待機(jī)存儲(chǔ)分區(qū)

通過(guò)它,系統(tǒng)會(huì)根據(jù)應(yīng)用使用模式動(dòng)態(tài)確定應(yīng)用資源請(qǐng)求的優(yōu)先級(jí); 應(yīng)用待機(jī)存儲(chǔ)分區(qū)有助于系統(tǒng)根據(jù)應(yīng)用的使用時(shí)間新近度和使用頻率對(duì)應(yīng)用資源請(qǐng)求確定優(yōu)先級(jí)

根據(jù)應(yīng)用使用模式,每個(gè)應(yīng)用都會(huì)被放置在五個(gè)優(yōu)先級(jí)存儲(chǔ)分區(qū)之一中; 系統(tǒng)會(huì)根據(jù)應(yīng)用所在的存儲(chǔ)分區(qū)限制每個(gè)應(yīng)用可用的設(shè)備資源

  • Android 6.0(API 級(jí)別 23)引入了低電耗模式和應(yīng)用待機(jī)模式

低電耗模式會(huì)在屏幕處于關(guān)閉狀態(tài)且設(shè)備處于靜止?fàn)顟B(tài)時(shí)限制應(yīng)用行為; 應(yīng)用待機(jī)模式會(huì)將未使用的應(yīng)用置于一種特殊狀態(tài),進(jìn)入這種狀態(tài)后,應(yīng)用的網(wǎng)絡(luò)訪(fǎng)問(wèn)、作業(yè)和同步會(huì)受到限制

  • Android 7.0(API 級(jí)別 24)限制了隱式廣播,并引入了隨時(shí)隨地使用低電耗模式
  • Android 8.0(API 級(jí)別 26)進(jìn)一步限制了后臺(tái)行為,例如在后臺(tái)獲取位置信息和釋放緩存的喚醒鎖定
  • Android 9(API 級(jí)別 28)引入了應(yīng)用待機(jī)存儲(chǔ)分區(qū),通過(guò)它,系統(tǒng)會(huì)根據(jù)應(yīng)用使用模式動(dòng)態(tài)確定應(yīng)用資源請(qǐng)求的優(yōu)先級(jí)

如何選擇合適的后臺(tái)解決方案

下面有一張圖完美的解答了這個(gè)問(wèn)題

  • 從上圖我們可以清晰的了解如何選擇后臺(tái)解決方案,如果是一個(gè)長(zhǎng)時(shí)間的http下載的話(huà)就使用DownloadManager
  • 否則的話(huà)就看是不是一個(gè)可以延遲的任務(wù),如果不可以就使用Foreground service
  • 如果是的話(huà)就看是不是可以由系統(tǒng)條件觸發(fā),如果是的話(huà)就使用WorkManager
  • 如果不是就看是不是需要在一個(gè)固定的時(shí)間執(zhí)行這個(gè)任務(wù),如果是的話(huà)就使用AlarmManager
  • 如果不是的話(huà)就使用WorkManager

WorkManager概述

  • 使用 WorkManager API 可以輕松地調(diào)度可延遲的工作以及預(yù)計(jì)即使您的設(shè)備或應(yīng)用重啟也會(huì)運(yùn)行的工作,即使在應(yīng)用退出或設(shè)備重啟時(shí)仍應(yīng)運(yùn)行的可延遲異步任務(wù)
  • 最高向后兼容到 API 14
  • 在運(yùn)行 API 23 及以上級(jí)別的設(shè)備上使用 JobScheduler
  • 在運(yùn)行 API 14-22 的設(shè)備上結(jié)合使用 BroadcastReceiver 和 AlarmManager
  • 添加網(wǎng)絡(luò)可用性或充電狀態(tài)等工作約束
  • 調(diào)度一次性或周期性異步任務(wù)
  • 監(jiān)控和管理計(jì)劃任務(wù)
  • 將任務(wù)鏈接起來(lái)
  • 確保任務(wù)執(zhí)行,即使應(yīng)用或設(shè)備重啟也同樣執(zhí)行任務(wù)
  • 遵循低電耗模式等省電功能

WorkManager使用

1 聲明依賴(lài)項(xiàng)

dependencies {
  def work_version = "2.3.1"

    // (Java only)
    implementation "androidx.work:work-runtime:$work_version"

    // Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"

    // optional - RxJava2 support
    implementation "androidx.work:work-rxjava2:$work_version"

    // optional - GCMNetworkManager support
    implementation "androidx.work:work-gcm:$work_version"

    // optional - Test helpers
    androidTestImplementation "androidx.work:work-testing:$work_version"
}

2 自定義一個(gè)繼承自Worker的類(lèi)

重寫(xiě)doWork方法,或者使用協(xié)程的話(huà),得繼承自CoroutineWorker。doWork方法有一個(gè)返回值,來(lái)標(biāo)記任務(wù)是否成功或者是否要retry; 返回值有三種,分別是Result.success(),Result.failure(),Result.retry()

執(zhí)行成功返回Result.success() 執(zhí)行失敗返回Result.failure() 需要重新執(zhí)行返回Result.retry()

override fun doWork(): Result {
    for (i in 1..3) {
        Thread.sleep(500)
        Log.i("aaa", "count: $i parameter: ${inputData.getString("parameter1")}")
    }
    return Result.success(Data.Builder().putString("result1", "value of result1").build())
}

3 選擇worker執(zhí)行的條件

//添加約束
val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .setRequiresBatteryNotLow(false)
                .setRequiresCharging(false)
                .setRequiresDeviceIdle(false)
                .setRequiresStorageNotLow(false)
                .build()
  //對(duì)一次性執(zhí)行添加約束,如果返回faliure或者retry的話(huà)就在適當(dāng)?shù)募s束條件下執(zhí)行worker
  val request = OneTimeWorkRequestBuilder<CountWorker>()
                .setConstraints(constraints)
                .setInputData(Data.Builder().putString("parameter1", "value of parameter1").build())
                .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.HOURS)
                .build()
 WorkManager.getInstance(context).enqueue(request)
//或者定時(shí)每隔一個(gè)小時(shí)執(zhí)行任務(wù)  
val periodicWorkRequest = PeriodicWorkRequest.Builder(AppsWorker::class.java,
                                    1, TimeUnit.HOURS)
                                     .setConstraints(constraints)
                                     .build();
 WorkManager.getInstance(context).enqueue(periodicWorkRequest)

需要注意的是類(lèi)似于JobSceeduler,周期性執(zhí)行的任務(wù)最少間隔時(shí)間不能小于15mins

4 下面貼出自定義worker類(lèi)的全部源碼

class CountWorker(context: Context, parameters: WorkerParameters)
    : Worker(context, parameters) {
    companion object {
        fun enqueue(context: ComponentActivity) {
            val constraints = Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED)
                    .setRequiresBatteryNotLow(false)
                    .setRequiresCharging(false)
                    .setRequiresDeviceIdle(false)
                    .setRequiresStorageNotLow(false)
                    .build()
            val request = OneTimeWorkRequestBuilder<CountWorker>()
            		//-----1-----添加約束
                    .setConstraints(constraints)
                    //-----2----- 傳入執(zhí)行worker需要的數(shù)據(jù)
                    .setInputData(Data.Builder().putString("parameter1", "value of parameter1").build())
                    //-----3-----設(shè)置避退策略
                    .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.HOURS)
                    .build()
             //-----4-----將任務(wù)添加到隊(duì)列中
            //WorkManager.getInstance(context).enqueue(request)
            //或者采用uniqueName執(zhí)行
        	WorkManager.getInstance(context).beginUniqueWork("uniqueName", ExistingWorkPolicy.REPLACE, request).enqueue()
            //-----5-----對(duì)任務(wù)加入監(jiān)聽(tīng)
            WorkManager.getInstance(context).getWorkInfoByIdLiveData(request.id).observe(context, Observer {
            	//-----8----獲取doWork中傳入的參數(shù)
                Log.i("aaa", "workInfo ${it.outputData.getString("result1")} ${it.state}: ")
            })
            //或者采用tag的方式監(jiān)聽(tīng)狀態(tài)
            WorkManager.getInstance(context).getWorkInfosByTagLiveData("tagCountWorker").observe(context, Observer {
            Log.i("aaa", "workInfo tag-- ${it[0].outputData.getString("result1")} ${it[0].state}: ")
        	})
        	//或者采用uniqueName的形式監(jiān)聽(tīng)任務(wù)執(zhí)行的狀態(tài)
        	WorkManager.getInstance(context).getWorkInfosForUniqueWorkLiveData("uniqueName").observe(context, Observer {
            Log.i("aaa", "workInfo uniqueName-- ${it[0].outputData.getString("result1")} ${it[0].state}: ")
       	 })
        }
    }
    override fun doWork(): Result {
        for (i in 1..3) {
            Thread.sleep(500)
            //-----6-----獲取傳入的參數(shù)
            Log.i("aaa", "count: $i parameter: ${inputData.getString("parameter1")}")
        }
       //-----7-----傳入返回的參數(shù)
        return Result.success(Data.Builder().putString("result1", "value of result1").build())
    }
}
  • 為了測(cè)試方便,我把執(zhí)行的代碼寫(xiě)在了enqueue中了,在enqueue中,我們首先在注釋1處添加了約束
  • 在注釋2處添加了執(zhí)行worker需要的參數(shù)。這個(gè)參數(shù)可以在doWork中獲取到,如注釋6處所示;傳入的數(shù)據(jù)不能超過(guò)10kb
  • 注釋3處我們?cè)O(shè)置了避退策略,如果我們的一次性任務(wù)返回了retry,這里就可以起作用了,避退策略有兩種方式。一種是指數(shù)級(jí)的EXPONENTIAL,還有一種是線(xiàn)性的LINEAR
  • 然后注釋4處將任務(wù)加入到隊(duì)列中,這里僅僅是加入隊(duì)列,并不能保證執(zhí)行,因?yàn)閃orkManager主要的定位就是針對(duì)可延遲的任務(wù),它需要根據(jù)添加的約束和系統(tǒng)自身的情況來(lái)做出什么時(shí)間執(zhí)行這個(gè)任務(wù)
  • 注釋5處可以根據(jù)request的id獲取到任務(wù)的執(zhí)行狀態(tài),返回值是一個(gè)LiveData類(lèi)型的,并將其加入到生命周期觀(guān)察序列中;所以當(dāng)任務(wù)的執(zhí)行狀態(tài)發(fā)生變化的時(shí)候就會(huì)在注釋8處打印信息
  • 我們還可以在任務(wù)執(zhí)行結(jié)束的時(shí)候傳入需要返回的參數(shù),但是只能在success和failure的時(shí)候傳入,傳入的數(shù)據(jù)可以再注釋8處獲取

5 執(zhí)行任務(wù)的方式

如果我們想要以鏈?zhǔn)綀?zhí)行一系列任務(wù),如圖所示,我們可以使用:

 WorkManager.getInstance(context).beginWith(requestA).then(requestB).enqueue()

如果我們的任務(wù)A和任務(wù)B之間沒(méi)有關(guān)系,需要在任務(wù)A和B都完成的情況下執(zhí)行任務(wù)C的話(huà),如圖所示,這時(shí)候就可以這么調(diào)用:

WorkManager.getInstance(context).beginWith(listOf(requestA,requestB)).then(requestC).enqueue()

如果我們想要AB和CD并行的執(zhí)行完,然后執(zhí)行E的話(huà),如圖所示,可以采用:

val continuation1 = WorkManager.getInstance(context).beginWith(requestA).then(requestB)
val continuation2 = WorkManager.getInstance(context).beginWith(requestC).then(requestD)
WorkContinuation.combine(listOf(continuation1, continuation2)).then(requestE).enqueue()

需要注意的是任務(wù)一旦發(fā)起,任務(wù)是可以保證一定會(huì)被執(zhí)行的,就算退出應(yīng)用,甚至重啟手機(jī)都阻止不了他;但可能由于添加了環(huán)境約束等原因會(huì)在不確定的時(shí)間執(zhí)行罷了

6 取消任務(wù)的執(zhí)行

//通過(guò)request.id取消任務(wù)
WorkManager.getInstance(context).cancelWorkById(request.id)
//通過(guò)request的tag取消任務(wù)
WorkManager.getInstance(context).cancelAllWorkByTag("tag")
//通過(guò)request的uniqueName取消任務(wù)
WorkManager.getInstance(context).cancelUniqueWork("uniqueName")
//取消所有的work任務(wù)
WorkManager.getInstance(context).cancelAllWork()

以上可以看到可以通過(guò)四種方式取消任務(wù)

到此這篇關(guān)于Android Jetpack庫(kù)重要組件WorkManager的使用的文章就介紹到這了,更多相關(guān)Android Jetpack WorkManager內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

尼木县| 神池县| 义马市| 江津市| 通渭县| 武城县| 墨竹工卡县| 金华市| 日照市| 灵台县| 松桃| 沙河市| 黎川县| 富宁县| 济源市| 镇原县| 申扎县| 宝丰县| 迁安市| 威宁| 西畴县| 康定县| 秦安县| 汉寿县| 武夷山市| 淅川县| 板桥市| 秭归县| 雷山县| 宜州市| 平湖市| 乌拉特前旗| 镇赉县| 全州县| 辉南县| 洪雅县| 洪泽县| 惠来县| 山西省| 共和县| 广饶县|