就如Google在IO大會上所說,WorkManager用於處理要被確保執行的任務,所以免不了的需要提供一些方式,讓Worker可以在狀況允許時重新啟動。例如在傳遞檔案時遭遇斷線或是低電量時,WorkManage可以在網路恢復或是充電狀況下,直接執行該執行的Worker。
透過設定Constraints,WorkManager可以達到預期的效果。
How dose the Constraints work?
一樣的從簡單的使用範例出發,首先先以在充電下進行為條件建立Constraints:
Constraints myConstraints = new Constraints.Builder().setRequiresCharging(true).build(); |
Constraints的constructor很簡單,只是記錄條件設定的狀態:
// In Constraints |
接著就是透過WorkRequest存放在WorkSpec裡面:
OneTimeWorkRequest compressionWork = new OneTimeWorkRequest.Builder(CompressWorker.class) |
接著這個constraints
會在哪裡被使用呢?在WorkSpec中只有一個函式hasConstraints
會使用到。接著追朔使用這函式的位置,則會找到GreedyScheduler.schedule()
:
// In GreedyScheduler |
如果WorkSpec設有Constraints,則此WorkSpec就不會被執行。而是傳給WorkConstraintsTracker,再傳給其所擁有的ConstraintController:
// In WorkConstraintsTracker |
以下可透過WorkConstraintsTracker的constructor得知其擁有哪些ConstraintController:
// In WorkConstraintsTracker |
由於範例設定的條件是在手機充電時,所以前面的controller.replace()
,就是BatteryChargingController.replace()
。
為了之後分析上流暢,在這先看一下BatteryChargingController的constructor:
// In BatteryChargingController |
所以外面的WorkConstraintsTracker變成這邊的callback
,並透過靜態類別Trackers拿到對應的Tracker。
Trackers會在建立的階段初始化所有會被用到的Tracker:
// In Trackers |
再回到BatteryChargingController.replace()
,由於BatteryChargingController沒有複寫這函示,所以是ConstraintController.replace()
:
// In ConstraintController |
這邊首先會用hasConstraint()
,也就是BatteryChargingController.hasConstraint()
,來判斷WorkSpec是否有設置對應的constraints
。
有則將符合條件的WorkSpec的Id存起來,並將BatteryChargingController透過addListener()
傳入mTracker
。
到這,我們可以簡單總結一下WorkConstraintsTracker的結構:
WorkConstraintsTracker { |
接著,BatteryChargingTracker本身和其父類BroadcastReceiverConstraintTracker並沒有複寫addListener()
,所以直接看到最上層父類ConstraintTracker:
// In ConstraintTracker |
看到startTracking
:
// In BroadcastReceiverConstraintTracker |
很明顯的,這代表當手機接受充電時,會發出一個Broadcast,而這邊則註冊了Receiver來接收:
// In BroadcastReceiverConstraintTracker |
到這邊,就可以確定開始監聽手機充電的狀態,也可以帶出一個觀念:
- 整個Constraints的機制的啟動,並不是在設定Constraints的時候;而是在執行
enqueue
,且WorkSpec即將透過Scheduler進入排程的時候。
所以當收到手機充電的Broadcast後,會直接呼叫onBroadcastReceive()
,此函式則在BatteryChargingTracker中實作:
// In BatteryChargingTracker |
不論是何種狀況,都會走到setState()
,記錄充電狀態後,透過listener,也就是BatteryChargingController回傳:
// In BatteryChargingTracker |
不過onConstraintChanged
的實作是在ConstraintController:
// In ConstraintController |
一樣紀錄當前狀態,在走到updateCallback()
,透過mCallback
,也就是WorkConstraintsTracker,往外回傳已經滿足條件的WorkSpec的Id:
// In ConstraintController |
這裡會再次確認並拿出已經滿足條件的WorkSpec的Id,再透過callback傳回去。一般來說,這裡的mCallback
會是GreedyScheduler,所以這些Id會再經由startWork()
重新進入執行的流程中:
// In GreedyScheduler |
到這分析完從建立Constraints,到如何被執行的流程。主要流程可以簡化如下:
- 建立Constraints
- 建立Worker,與Constraints一起當成參數建立WorkerRequest,並透過Worker建立WorkSpec。
- 將WorkSpec放入資料庫。
- 使用BroadcastReceiver啟動監聽程序。
- 收到Broadcast後取出WorkSpec。
- 重新使用WorkSpec來執行Worker。