Android JetPack-WorkManager詳解

WorkManager

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

在后臺,WorkManager根據以下條件使用基礎的作業調度服務:


不同版本的調度

WorkManager的優勢

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

現在,WorkManager庫已經成熟,并且極大的減輕了Android開發的工作量,還更加省電、可靠、性能優越

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

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

之所以WorkManager能進程退出、奔潰、重啟機器情況下也能保證完成提交給系統的延時任務是依賴與數據的持久化

可以看到文件、數據庫的使用,這是workmanager自己創建的

以后要是吹WorkManager源碼分析、底層實現分析的牛逼

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

圍觀一下數據庫


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()調用不要在application中的attachBaseContext方法調用

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

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

剩下的代碼基本分為三步
1、創建
2、設置約束條件
3、執行

當然 中間可以觀察者模式調用,觀察調用進度、數據,也可以暫停、取消操作

下面看看代碼使用WorkManager

創建WorkRequest 并將其加入隊列

  • 一次性任務 OneTimeWorkRequest

    執行工作器的確切時間還取決于 WorkRequest 中使用的Constraints約束和系統優化。WorkManager 經過設計,在滿足這些約束的情況下提供可能的最佳行為


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

        //定義傳入到任務中的數據
        Data inputData = new Data.Builder().putString("chris", "數據").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任務執行
public class MainWorker extends Worker {
    private static final String TAG = "MainWorker";

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

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

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

        return Result.success(outputData);
    }
}

  • 加入隊列執行
 WorkManager.getInstance()
                .beginUniqueWork("unique",
                        ExistingWorkPolicy.REPLACE//設置任務不重復
                        , request)
                .enqueue();
  • 觀察工作狀態接收數據
 //接收任務中回來的數據、進度
        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);

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

                    }
                });

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

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

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


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

  • 任務鏈

多任務組合一個任務鏈

 WorkManager.getInstance(this)

                //request,request2并發執行
                .beginWith(Arrays.asList(request, request2))
                //request1 request2順序執行
                .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);

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

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

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

adb 查看自己app的work


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

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。