WorkManager
WorkManager可以用來執行一個在特定條件下觸發執行的延時任務。比如我設定觸發條件是,手機有網路連線的時候才會觸發。當我們斷網的時候開啟app,我們的任務不會立即執行,當手機聯網之後才會觸發。
這樣我們就可以利用WorkManager輕鬆實現某些條件下觸發的延時任務。
引入
在專案中引入WorkManager包
implementation "android.arch.work:work-runtime:1.0.0-alpha01" implementation "android.arch.work:work-firebase:1.0.0-alpha01"
使用
首先我們要建立我們的任務類。
ublic class MyWork extends Worker { @NonNull @Override public WorkerResult doWork() { //執行任務 return WorkerResult.SUCCESS; } }
doWork會在條件滿足的時候觸發。
再來看看怎麼定義觸發規則並把任務新增到WorkManager中。
Constraints constraints = new Constraints.Builder()//定義觸發規則 .setRequiredNetworkType(NetworkType.CONNECTED)//觸發規則是當有絡連線的時候執行 .build(); Data data = new Data.Builder()//新增資料 .putString("data","你好") .build(); OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWork.class)//建立WorkRequest .setConstraints(constraints) .setInputData(data) .build(); WorkManager.getInstance().enqueue(workRequest);//新增到WorkManager去管理任務。
Constraints
用來定義任務的觸發條件,網路狀態說明:
狀態 | 說明 |
---|---|
NOT_REQUIRED | 沒有要求 |
CONNECTED | 網路連線 |
UNMETERED | 連線無限流量的網路 |
METERED | 連線按流量計費的網路 |
NOT_ROAMING | 連線非漫遊網路 |
除了網路連線的狀態還有下面的觸發條件可以選擇:
setRequiresBatteryNotLow(true)//不在電量不足時執行 setRequiresCharging(true)//在充電時執行 setRequiresStorageNotLow(true)//不在儲存容量不足時執行 setRequiresDeviceIdle(true)//在待機狀態執行
Data
用來建立要傳遞給worker的引數,傳入方式是鍵值對。
OneTimeWorkRequest
這個Request說明只會觸發一次。如果需要執行週期性任務可以使用PeriodicWorkRequest。
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest .Builder(MyWorker.class,15, TimeUnit.SECONDS) .setConstraints(constraints) .setInputData(data) .build();
取消任務
UUID workId = workRequest.getId(); WorkManager.getInstance().cancelByWorkId(workId);
Worker接收並返回引數
public class MyWork extends Worker { @NonNull @Override public WorkerResult doWork() { String name = getInputData().getString("data", "");//獲取資料 //做些什麼 Data data = new Data.Builder().putString("out","返回點什麼").build(); setOutputData(data);//返回資料 return WorkerResult.SUCCESS; } }
拿到worker返回的資料
要拿到返回的資料需要利用回撥。
WorkManager.getInstance().getStatusById(workRequest.getId())//通過workRequest的id獲取 .observe(this, new Observer<WorkStatus>() { @Override public void onChanged(@Nullable WorkStatus workStatus) { String data = workStatus.getOutputData().getString("out",""); Log.d("MainActivity", data); } });
第一個引數是LifecycleOwner,回撥同步生命週期,是為了防止我們頁面退出之後可能造成的記憶體洩漏。
我們從第二個回撥裡面可以拿到返回的資料。
在這裡我們要著重注意資料的大小,如果資料太大就會報下面的異常:

對,新增到Data的資料不能大於10KB,本來我也以為是10M(火星換演算法10240KB=10KB),但是我的資料才十幾KB,怎麼會超出範圍,然後從原始碼中發現:


鏈式任務
有些時候任務執行前後順序會影響到結果,需要順序執行某些任務,又或者後面的任務需要使用前面任務得出的結果,這個時候我們就可以使用鏈式任務。
1、ABC先後執行
WorkManager.getInstance().beginWith(A).then(B).then(C).enqueue();

2、A,B沒有先後順序,但是A、B均為C的前驅任務
WorkManager.getInstance().beginWith(A,B).then(C).enqueue();

3、A、B和C、D鏈式執行,執行完之後在執行E
WorkContinuation workContinuation1 = WorkManager.getInstance().beginWith(A).then(B); WorkContinuation workContinuation2 = WorkManager.getInstance().beginWith(C).then(D); WorkContinuation workContinuation3 = WorkContinuation.combine(workContinuation1,workContinuation2).then(E).enqueue();

強大的生命力
WorkManager有著強大的存活能力,當我們斷網的時候開啟app,這個時候任務沒有滿足觸發條件,退出app(程序沒有被清除)。這時候連上網路依然會執行任務。
但是當我們結束程序就會出現下面的情況。
我們進行下面的操作。
1、斷開網路
2、開啟app,這個時候不會執行
3、殺掉應用程序
4、開啟網路,第一次的任務沒有執行
5、開啟app
然後會發現,任務執行了兩次。第一次的執行是第一次執行後,加入了任務佇列,但還沒有執行的任務。
第二次執行是我們第二次開啟,因為滿足網路連線條件立即執行。
這是 WorkManager 的另一個特點,一旦發起一個任務,任務是可以保證一定會被執行的,就算退出應用,甚至重啟手機都阻止不了他。但可能由於添加了環境約束等原因,它執行的時間是不確定的。
原理我們利用網上的一個圖片說明。
當應用正在執行時,它會在當前的程序中啟用一個子執行緒執行。應用沒有執行的情況下啟用, 它則會自己選擇一種合適的方式在後臺執行。具體是什麼方式和 Android 的版本和依賴環境有關 :

是不是很強大
拜拜~~