WorkManager
WorkManager是Google最新的后臺任務調(diào)度解決方案,Google計劃2020年11月1日開始全面統(tǒng)一在Android上使用WorkManager處理后臺任務的調(diào)度處理工作
在后臺撇眯,WorkManager根據(jù)以下條件使用基礎的作業(yè)調(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ù)的持久化
以后要是吹WorkManager源碼分析营搅、底層實現(xiàn)分析的牛逼
主要就拿JobScheduler云挟、JobService、sqlite(room)转质、sp园欣、GreedyScheduler、BroadcastReceiver休蟹、Alarm沸枯、線程池、Handler赂弓、LifecycleService(Androidx)吹
圍觀一下數(shù)據(jù)庫
使用
使用比較簡單,首先添加必要的依賴注冊初始化
//依賴庫
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
剩下的代碼基本分為三步
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的日志顯示所有