Android JetPack-WorkManager詳解

WorkManager

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

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


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

WorkManager的優(yōu)勢

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

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

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

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

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

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

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

主要就拿JobScheduler、JobService、sqlite(room)、sp、GreedyScheduler、BroadcastReceiver、Alarm、線程池、Handler、LifecycleService(Androidx)吹

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


WorkManager DB
表結(jié)構(gòu)
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)用

對于老項目要使用的話,首先要對項目進(jìn)行遷移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、設(shè)置約束條件
3、執(zhí)行

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

下面看看代碼使用WorkManager

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

  • 一次性任務(wù) OneTimeWorkRequest

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


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

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

        //一次性任務(wù)
        OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(MainWorker.class)
                .setInputData(inputData)
                .setConstraints(constraints)
                .build();
  • 重復(fù)周期性任務(wù) PeriodicWorkRequest
    最小周期不能低于15分鐘,如果設(shè)置小于15分鐘,也是按15分鐘的周期運(yùn)行
    日志會打印:Interval duration lesser than minimum allowed value; Changed to 900000"
     //一天一次周期任務(wù)
       PeriodicWorkRequest saveRequest =
               new PeriodicWorkRequest.Builder(MainWorker.class, 1, TimeUnit.DAYS)
                       .setConstraints(constraints)
                       .build();
  • woker任務(wù)執(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傳入進(jìn)來的數(shù)據(jù)
        String data = getInputData().getString("chris");
        Log.e(TAG, "中取到了數(shù)據(jù)" + data);
        //把任務(wù)中的數(shù)據(jù)回傳到activity中
        Data outputData = new Data.Builder().putString("name", "chris").build();

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

        return Result.success(outputData);
    }
}

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

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

                    }
                });

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

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

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


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

  • 任務(wù)鏈

多任務(wù)組合一個任務(wù)鏈

 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();

多任務(wù)鏈合并一個任務(wù)鏈

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

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

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

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

   //創(chuàng)建一個唯一周期重復(fù)工作鏈     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的日志顯示所有

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容