Android JetPack-WorkManager詳解

WorkManager

WorkManager是Google最新的后臺任務調(diào)度解決方案,Google計劃2020年11月1日開始全面統(tǒng)一在Android上使用WorkManager處理后臺任務的調(diào)度處理工作

在后臺撇眯,WorkManager根據(jù)以下條件使用基礎的作業(yè)調(diào)度服務:


不同版本的調(diào)度

WorkManager的優(yōu)勢

  • 最高向后兼容到 API 14
    • 在運行 API 23 及以上級別的設備上使用 JobScheduler
    • 在運行 API 14-22 的設備上結合使用 BroadcastReceiver 和 AlarmManager
  • 添加網(wǎng)絡可用性或充電狀態(tài)等工作約束,根據(jù)添加的約束條件智能的啟動后臺任務
  • 調(diào)度一次性或周期性異步任務
  • 監(jiān)控和管理計劃任務
  • 將任務鏈接起來,可以給多個任務進行串行报嵌、并行調(diào)度,甚至多個鏈多個鏈的串行并行
  • 確保任務執(zhí)行,即使應用或設備重啟也同樣執(zhí)行任務,依賴于room的持久化實現(xiàn)
  • 遵循低電耗模式等省電功能,更省電

現(xiàn)在熊榛,WorkManager庫已經(jīng)成熟,并且極大的減輕了Android開發(fā)的工作量,還更加省電沪蓬、可靠、性能優(yōu)越

但是要注意WorkManager適用于及時性不高的任務,一些高及時性的場景不要使用,比如你的訂單創(chuàng)建那就要立馬發(fā)送請求,及時響應結果

假如說你的訂單是離線(也就是沒有網(wǎng)絡)也需要創(chuàng)建成功,等網(wǎng)絡再進行提交,那么這種場景就比較適合使用WorkManager,能極大減少工作量 ,還能一定程度上保證訂單不會丟失

之所以WorkManager能進程退出来候、奔潰跷叉、重啟機器情況下也能保證完成提交給系統(tǒng)的延時任務是依賴與數(shù)據(jù)的持久化

可以看到文件、數(shù)據(jù)庫的使用,這是workmanager自己創(chuàng)建的

以后要是吹WorkManager源碼分析营搅、底層實現(xiàn)分析的牛逼

主要就拿JobScheduler云挟、JobService、sqlite(room)转质、sp园欣、GreedyScheduler、BroadcastReceiver休蟹、Alarm沸枯、線程池、Handler赂弓、LifecycleService(Androidx)吹

圍觀一下數(shù)據(jù)庫


WorkManager DB
表結構
image.png

使用

使用比較簡單,首先添加必要的依賴注冊初始化

//依賴庫
 def work_version = "2.3.0-alpha01"
 implementation "androidx.work:work-runtime:$work_version"
//清單文件
 <provider
            android:name="androidx.work.impl.WorkManagerInitializer"
            android:authorities="${applicationId}.workmanager-init"
            android:directBootAware="false"
            android:exported="false"
            android:multiprocess="true"
            tools:node="remove"
            tools:targetApi="n" />
//application
public class Myapplication extends Application implements Configuration.Provider {

    @Override
    public void onCreate() {
        super.onCreate();
        Configuration myConfig = new Configuration.Builder()
                .setMinimumLoggingLevel(android.util.Log.VERBOSE)
                .build();
        WorkManager.initialize(getBaseContext(), myConfig);
    }
    @NonNull
    @Override
    public Configuration getWorkManagerConfiguration() {
        return new Configuration.Builder()
                .setMinimumLoggingLevel(android.util.Log.INFO)
                .build();
    }
}

如果不在manifest文件注冊application中初始化,可能會報以下錯

WorkManager is not initialized properly. You have explicitly disabled WorkManagerInitializer in your manifest, have not manually called WorkManager#initialize at this point, and your Application does not implement Configuration.Provider

WorkManager is already initialized. Did you try to initialize it manually without disabling WorkManagerInitializer? See WorkManager#initialize(Context, Configuration) or the class levelJavadoc for more information.

另外要注意:

WorkManager.getInstance()調(diào)用不要在application中的attachBaseContext方法調(diào)用

對于老項目要使用的話,首先要對項目進行遷移androidX,Android studio已經(jīng)可以一鍵遷移,修改buildToolsVersion 28以上绑榴、gradle3.2以上

classpath 'com.android.tools.build:gradle:3.2.0+'
android.useAndroidX=true
android.enableJetifier=true
遷移AndroidX

剩下的代碼基本分為三步
1、創(chuàng)建
2盈魁、設置約束條件
3翔怎、執(zhí)行

當然 中間可以觀察者模式調(diào)用,觀察調(diào)用進度、數(shù)據(jù),也可以暫停、取消操作

下面看看代碼使用WorkManager

創(chuàng)建WorkRequest 并將其加入隊列

  • 一次性任務 OneTimeWorkRequest

    執(zhí)行工作器的確切時間還取決于 WorkRequest 中使用的Constraints約束和系統(tǒng)優(yōu)化赤套。WorkManager 經(jīng)過設計飘痛,在滿足這些約束的情況下提供可能的最佳行為


        
        //任務約束條件
        Constraints constraints = new Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED)//聯(lián)網(wǎng)狀態(tài)
                .setRequiresBatteryNotLow(true)//非低電量
                .setRequiresDeviceIdle(true)//設備空閑
                .setRequiresStorageNotLow(true)//存儲空間足夠
                .setRequiresCharging(true)//充電狀態(tài)
                .setTriggerContentMaxDelay(20, TimeUnit.DAYS)//延時20天后執(zhí)行
                .build();

        //定義傳入到任務中的數(shù)據(jù)
        Data inputData = new Data.Builder().putString("chris", "數(shù)據(jù)").build();

        //一次性任務
        OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(MainWorker.class)
                .setInputData(inputData)
                .setConstraints(constraints)
                .build();
  • 重復周期性任務 PeriodicWorkRequest
    最小周期不能低于15分鐘,如果設置小于15分鐘,也是按15分鐘的周期運行
    日志會打印:Interval duration lesser than minimum allowed value; Changed to 900000"
     //一天一次周期任務
       PeriodicWorkRequest saveRequest =
               new PeriodicWorkRequest.Builder(MainWorker.class, 1, TimeUnit.DAYS)
                       .setConstraints(constraints)
                       .build();
  • woker任務執(zhí)行
public class MainWorker extends Worker {
    private static final String TAG = "MainWorker";

    public MainWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    //這個方法是在子線程執(zhí)行的
    @NonNull
    @Override
    public Result doWork() {
        //上傳,下載容握,同步數(shù)據(jù)
        Log.e(TAG, "執(zhí)行了");
        //獲取mainActivity傳入進來的數(shù)據(jù)
        String data = getInputData().getString("chris");
        Log.e(TAG, "中取到了數(shù)據(jù)" + data);
        //把任務中的數(shù)據(jù)回傳到activity中
        Data outputData = new Data.Builder().putString("name", "chris").build();

        //進度
        setProgressAsync(new Data.Builder().putInt("Progress",78).build());

        return Result.success(outputData);
    }
}

  • 加入隊列執(zhí)行
 WorkManager.getInstance()
                .beginUniqueWork("unique",
                        ExistingWorkPolicy.REPLACE//設置任務不重復
                        , request)
                .enqueue();
  • 觀察工作狀態(tài)接收數(shù)據(jù)
 //接收任務中回來的數(shù)據(jù)宣脉、進度
        WorkManager.getInstance().getWorkInfoByIdLiveData(request.getId())
                .observe(this, new Observer<WorkInfo>() {
                    @Override
                    public void onChanged(WorkInfo workInfo) {
                        //獲取進度
                        Data progress = workInfo.getProgress();
                        int Progress = progress.getInt("Progress", 0);

                        //獲取數(shù)據(jù)
                        String name = workInfo.getOutputData().getString("name");
                        Log.i(TAG, "取到了任務回傳的數(shù)據(jù)" + name);

                    }
                });

  • 任務的取消、暫停
 //取消所有
        WorkManager.getInstance(this).cancelAllWork();
        //取消某一個 如saveRequest
        WorkManager.getInstance().cancelWorkById(saveRequest.getId());

        //按標記取消 WorkRequest會取消所有具有此標記的工作
        WorkManager.getInstance().cancelAllWorkByTag(request.getStringId());

        //取消所有未完成的工作的工作鏈的名字:unique
        WorkManager.getInstance(this).cancelUniqueWork("unique");


有高級玩法,比如取消當前的執(zhí)行任務并將其 REPLACE 為新工作鏈

  • 任務鏈

多任務組合一個任務鏈

 WorkManager.getInstance(this)

                //request,request2并發(fā)執(zhí)行
                .beginWith(Arrays.asList(request, request2))
                //request1 request2順序執(zhí)行
                .then(request1).then(request2)
                .then(Arrays.asList(request1, request2))
                .enqueue();

多任務鏈合并一個任務鏈

 //兩個任務鏈
        WorkContinuation begin = WorkManager.getInstance(this).beginWith(Arrays.asList(request, request2));
        WorkContinuation then = WorkManager.getInstance(this).beginWith(request).then(request1);

        //多任務鏈合并剔氏,
        WorkContinuation thenEnd = WorkContinuation.combine(Arrays.asList(begin, then)).then(request);

        //多任務鏈執(zhí)行
        thenEnd.enqueue();

如果需要創(chuàng)建一個唯一單次工作鏈可以使用 WorkManager.beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest 代替 beginWith()

   //創(chuàng)建一個唯一周期重復工作鏈     WorkManager.getInstance(base).enqueueUniquePeriodicWork(TAG_Unique, ExistingPeriodicWorkPolicy.REPLACE, mPeriodicWorkRequest);

adb 查看自己app的work


adb shell am broadcast -a "androidx.work.diagnostics.REQUEST_DIAGNOSTICS"  appPackageName

執(zhí)行adb廣播之后,logcat過濾自己app的日志顯示所有

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末脖旱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子介蛉,更是在濱河造成了極大的恐慌萌庆,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件币旧,死亡現(xiàn)場離奇詭異践险,居然都是意外死亡,警方通過查閱死者的電腦和手機吹菱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門巍虫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鳍刷,你說我怎么就攤上這事占遥。” “怎么了输瓜?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵瓦胎,是天一觀的道長。 經(jīng)常有香客問我尤揣,道長搔啊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任北戏,我火速辦了婚禮负芋,結果婚禮上,老公的妹妹穿的比我還像新娘嗜愈。我一直安慰自己旧蛾,他們只是感情好,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布蠕嫁。 她就那樣靜靜地躺著锨天,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拌阴。 梳的紋絲不亂的頭發(fā)上绍绘,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音迟赃,去河邊找鬼陪拘。 笑死,一個胖子當著我的面吹牛纤壁,可吹牛的內(nèi)容都是我干的左刽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼酌媒,長吁一口氣:“原來是場噩夢啊……” “哼欠痴!你這毒婦竟也來了?” 一聲冷哼從身側響起秒咨,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤喇辽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后雨席,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菩咨,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年陡厘,在試婚紗的時候發(fā)現(xiàn)自己被綠了抽米。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡糙置,死狀恐怖云茸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谤饭,我是刑警寧澤标捺,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站揉抵,受9級特大地震影響宜岛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜功舀,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一萍倡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辟汰,春花似錦列敲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至翩蘸,卻和暖如春所意,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工扶踊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留泄鹏,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓秧耗,卻偏偏與公主長得像备籽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子分井,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348