1 簡介
WorkManager是Jetpack組件庫中的一個組件导匣,主要用于處理立即執(zhí)行、長時間運行秦躯、可延遲執(zhí)行的并且保證必須執(zhí)行的后臺操作任務郑叠。例如上傳日志,定時上傳數據产禾,定時下載數據排作,定時備份數據等等。即使APP退出或者進程被殺亚情,任務依舊可以執(zhí)行妄痪,不過需要注意的是目前WorkManager在Google Pixel手機上可以完美使用,但是在其他品牌手機使用有一定的問題楞件。
WorkManager可處理的3種永久性工作:
- 立即執(zhí)行:必須立即開始且很快就完成的任務衫生。
- 長時間運行:運行時間可能較長(有可能超過10分鐘)的任務。
- 可延期執(zhí)行:延期開始并且可以定期運行的預定任務土浸。
類型 | 周期 | 使用方式 |
---|---|---|
立即 | 一次性 | OneTimeWorkRequest 和 Worker罪针。如需處理加急工作,請對 OneTimeWorkRequest 調用 setExpedited()黄伊。 |
長期運行 | 一次性或定期 | 任意 WorkRequest 或 Worker泪酱。在工作器中調用 setForeground() 來處理通知。 |
可延期 | 一次性或定期 | PeriodicWorkRequest 和 Worker。 |
Google Developer文檔:https://developer.android.google.cn/topic/libraries/architecture/workmanager
原理:
WorkManager引入后墓阀,使用Room將任務存入數據庫毡惜,然后使用系統(tǒng)服務區(qū)執(zhí)行這些任務,這樣就實現了即使APP集成被殺斯撮,APP被強制退出的時候经伙,任務依然能被執(zhí)行。同時WorkManager會在AndroidManifest.xml中注冊receiver和service吮成,用來接收系統(tǒng)系統(tǒng)的廣播橱乱,比如網絡狀態(tài)辜梳、低電量粱甫、低內存、手機空閑等作瞄,來執(zhí)行附帶約束的任務茶宵。
2 使用
2.1 添加依賴
dependencies {
//WorkManager依賴
def work_version = "2.7.1"
implementation "androidx.work:work-runtime:$work_version"
...
}
示例代碼使用了ViewBinding
,需要開啟ViewBinding
宗挥。
android{
...
//開啟ViewBinding
viewBinding {
enabled = true
}
}
2.2 創(chuàng)建Activity
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
@RequiresApi(Build.VERSION_CODES.M)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
initView()
}
@RequiresApi(Build.VERSION_CODES.M)
private fun initView() {
...
}
}
XML中有幾個按鈕測試對應的后臺任務乌庶。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:text="執(zhí)行單次后臺任務"
android:textAllCaps="false" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:text="執(zhí)行單次后臺任務-發(fā)送數據"
android:textAllCaps="false" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:text="執(zhí)行多個后臺任務-按順序"
android:textAllCaps="false" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:text="執(zhí)行多個后臺任務-集合形式"
android:textAllCaps="false" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:text="周期性重復執(zhí)行后臺任務"
android:textAllCaps="false" />
<Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:text="附帶約束條件執(zhí)行后臺任務"
android:textAllCaps="false" />
</LinearLayout>
2.3 功能測試
2.3.1 執(zhí)行單次后臺任務
創(chuàng)建SimpleWorker
,繼承Worker
契耿,實現dowWork()
方法瞒大,dowWork()
是一個異步方法,它是在Runnable
的run
方法中調用的搪桂。doWork()
返回的Result
會通知 WorkManager
服務工作是否成功透敌,以及工作失敗時是否應重試工作。
Result
有3種:
-
Result.success()
:工作成功完成踢械。 -
Result.failure()
:工作失敗酗电。 -
Result.retry()
:工作失敗,應根據其重試政策在其他時間嘗試内列。
class SimpleWorker(context: Context, workParams: WorkerParameters) :
Worker(context, workParams) {
companion object {
const val TAG = "---SimpleWorker"
}
/**
* doWork() 返回的 Result 會通知 WorkManager 服務工作是否成功撵术,以及工作失敗時是否應重試工作。
* Result.success():工作成功完成话瞧。
* Result.failure():工作失敗嫩与。
* Result.retry():工作失敗,應根據其重試政策在其他時間嘗試交排。
*
* 這是一個后臺任務蕴纳,是異步的,在Runnable中執(zhí)行个粱。
*/
override fun doWork(): Result {
Log.d(TAG, "doWork: work start...")
try {
Thread.sleep(3000)
} catch (e: IOException) {
e.printStackTrace()
return Result.failure()
} finally {
Log.d(TAG, "doWork: work end...")
}
return Result.success()
}
}
在MainActivity
的initView()
方法中執(zhí)行該單次任務古毛。
步驟:
1、構建OneTimeWorkRequest
。
2稻薇、調用WorkManager.getInstance(this).enqueue()
提交任務到隊列嫂冻。
//單次后臺任務
binding.button1.setOnClickListener {
//構建WorkRequest
val oneTimeWorkRequest =
OneTimeWorkRequest.Builder(SimpleWorker::class.java).build()
//調用enqueue()方法將WorkRequest提交到WorkManager任務隊列中
WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)
//取消任務
//取消所有任務
WorkManager.getInstance(this).cancelAllWork()
//取消指定任務
WorkManager.getInstance(this).cancelWorkById(oneTimeWorkRequest.id)
}
2.3.2 執(zhí)行單次后臺任務-傳遞數據
WorkManager
在執(zhí)行任務的時候,可以攜帶數據交給Worker
塞椎,Worker
中可以接收該數據桨仿,然后在doWork()
的返回結果中也可以返回數據給WorkManager
,WorkManager
可以通過LiveData
去接收返回的數據案狠。
創(chuàng)建SimpleDataWorker
類:
class SimpleDataWorker(context: Context, private val workParams: WorkerParameters) :
Worker(context, workParams) {
companion object {
const val TAG = "---SimpleDataWorker"
}
override fun doWork(): Result {
Log.d(TAG, "doWork: work start...")
//接收MainActivity中傳過來的數據
val inputData = workParams.inputData.getString("inputData")
Log.d(TAG, "doWork: receive data:$inputData")
//將數據再返回給MainActivity
val outputData = Data.Builder().putString("outputData", "Tree New Bee").build()
return Result.success(outputData)
}
}
在MainActivity
的initView()
方法中執(zhí)行該任務服傍。
步驟:
1、使用Data.Builder()
構造要傳遞的數據體骂铁。
2吹零、構造OneTimeWorkRequest
。
3拉庵、用WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.id).observe(this){}
來獲取LiveData
去監(jiān)聽狀態(tài)和數據變化灿椅。
4、調用WorkManager.getInstance(this).enqueue()
提交任務到隊列钞支。
//執(zhí)行單次后臺任務-傳遞數據
binding.button2.setOnClickListener {
//要發(fā)傳遞出去的數據
val inputData = Data.Builder().putString("inputData", "New Bee").build()
//構建WorkRequest
val oneTimeWorkRequest = OneTimeWorkRequest.Builder(SimpleDataWorker::class.java)
.setInputData(inputData).build()//設置要傳遞的數據
//通過LiveData接收BackgroundWorker2返回的數據
WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.id)
.observe(this) {
//RUNNING時茫蛹,outputData為null;SUCCEEDED時烁挟,才能獲取到數據婴洼。
Log.d(
SimpleDataWorker.TAG,
"state 1: ${it.state} outputData:${it.outputData.getString("outputData")}"
)
//當狀態(tài)處于完成時,也就是SUCCEEDED撼嗓、FAILED柬采、CANCELLED時,任務才結束静稻,才能去拿結果數據警没,不然獲取到的數據是null
if (it.state.isFinished) {
Log.d(
SimpleDataWorker.TAG,
"state 2: ${it.state} outputData:${it.outputData.getString("outputData")}"
)
}
}
//提交任務,任務加入隊列
WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)
}
getWorkInfoByIdLiveData
方法會回調一個WorkInfo
對象振湾,WorkInfo
中包含狀態(tài)和Worker
返回的數據杀迹。
只要當狀態(tài)是SUCCEEDED
、FAILED
押搪、CANCELLED
這3個的時候树酪,才表示任務結束,這時候才能去獲取數據大州,其他狀態(tài)獲取到的數據是null续语。
2.3.3 執(zhí)行多個后臺任務-按順序
先創(chuàng)建3個任務:
class OrderWorker1(context: Context, workParams: WorkerParameters) :
Worker(context, workParams) {
companion object {
private const val TAG = "---OrderWorker1"
}
override fun doWork(): Result {
Log.d(TAG, "doWork: start...")
return Result.success()
}
}
class OrderWorker2(context: Context, workParams: WorkerParameters) :
Worker(context, workParams) {
companion object {
private const val TAG = "---OrderWorker2"
}
override fun doWork(): Result {
Log.d(TAG, "doWork: start...")
return Result.success()
}
}
class OrderWorker3(context: Context, workParams: WorkerParameters) :
Worker(context, workParams) {
companion object {
private const val TAG = "---OrderWorker3"
}
override fun doWork(): Result {
Log.d(TAG, "doWork: start...")
return Result.success()
}
}
然后按順序執(zhí)行這3個任務,核心方法是beginWith()
和then()
厦画,beginWith()
可以做一些前置工作疮茄,比如初始化等等滥朱,then()
中可以做一些后續(xù)工作。只有當前一個任務執(zhí)行成功才會執(zhí)行下一個任務力试。
//執(zhí)行多個后臺任務-按順序
binding.button3.setOnClickListener {
val oneTimeWorkRequest1 =
OneTimeWorkRequest.Builder(OrderWorker1::class.java).build()
val oneTimeWorkRequest2 =
OneTimeWorkRequest.Builder(OrderWorker2::class.java).build()
val oneTimeWorkRequest3 =
OneTimeWorkRequest.Builder(OrderWorker3::class.java).build()
//按順序執(zhí)行1,2,3
WorkManager.getInstance(this)
.beginWith(oneTimeWorkRequest1)
.then(oneTimeWorkRequest2)
.then(oneTimeWorkRequest3)
.enqueue()
}
2.3.4 執(zhí)行多個后臺任務-集合方式
集合方式和2.3.3中按順序執(zhí)行沒有什么大的區(qū)別徙邻,只不過是把多個任務放在集合中,然后再交給WorkManager
畸裳,同樣可以控制順序缰犁。
//執(zhí)行多個后臺任務-集合方式
binding.button4.setOnClickListener {
val oneTimeWorkRequest1 =
OneTimeWorkRequest.Builder(OrderWorker1::class.java).build()
val oneTimeWorkRequest2 =
OneTimeWorkRequest.Builder(OrderWorker2::class.java).build()
val oneTimeWorkRequest3 =
OneTimeWorkRequest.Builder(OrderWorker3::class.java).build()
val oneTimeWorkRequests = mutableListOf<OneTimeWorkRequest>()
oneTimeWorkRequests.add(oneTimeWorkRequest2)
oneTimeWorkRequests.add(oneTimeWorkRequest3)
//先執(zhí)行2,3怖糊,再執(zhí)行1
WorkManager.getInstance(this).beginWith(oneTimeWorkRequests)
.then(oneTimeWorkRequest1)
.enqueue()
}
2.3.5 周期性重復執(zhí)行后臺任務
周期性重復執(zhí)行任務就可以實現類似日志上傳的功能帅容,WorkManager
要求的任務重復周期不能小于15分鐘。
周期任務的WorkRequest
對象是PeriodicWorkRequest
伍伤。
//周期性重復執(zhí)行后臺任務
binding.button5.setOnClickListener {
//重復周期最少設置15分鐘并徘,少于15分鐘編譯器會報錯
val periodicWorkRequest =
PeriodicWorkRequest.Builder(SimpleWorker::class.java, 15, TimeUnit.MINUTES)
.build()
//監(jiān)聽狀態(tài)和數據變化
WorkManager.getInstance(this).getWorkInfoByIdLiveData(periodicWorkRequest.id)
.observe(this) {
Log.d(SimpleWorker.TAG, "state: ${it.state}")
if (it.state.isFinished) {
Log.d(SimpleWorker.TAG, "work finished...")
}
}
//提交任務,任務加入隊列
WorkManager.getInstance(this).enqueue(periodicWorkRequest)
}
2.3.6 附帶約束條件執(zhí)行后臺任務
附帶約束條件的任務是為了對APP性能進行優(yōu)化嚷缭,比如該任務只在聯網的時候才能進行饮亏,只有在充電的時候才能進行耍贾,只有在空閑時期(沒有其他大量服務在運行)的時候才能進行阅爽,這樣就能降低APP功耗,充分利用手機性能荐开。
//附帶約束條件執(zhí)行后臺任務
binding.button6.setOnClickListener {
//約束條件
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)//聯網中
.setRequiresCharging(true)//充電中
.setRequiresBatteryNotLow(true)//非低電量
// .setRequiresDeviceIdle(true)//手機空閑中
.setRequiresStorageNotLow(true)//非低內存
.build()
val oneTimeWorkRequest = OneTimeWorkRequest.Builder(SimpleWorker::class.java)
.setConstraints(constraints)//設置約束
.build()
//提交任務付翁,任務加入隊列
WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)
}
完整源碼可以在公號【木水Code】發(fā)送"WorkManager"進行下載。
3 源碼流程圖
源碼流程分析主要分三部分:
- WorkManager初始化過程
- WorkManager執(zhí)行無約束條件的任務
- WorkManager執(zhí)行有約束條件的任務
閱讀源碼的過程中結合該流程圖晃听,能更加快速理解百侧,加深記憶。
4 源碼分析
4.1 WorkManager初始化
在MainActivity
中能扒,調用了WorkManager.getInstance(this)
佣渴。
public static @NonNull WorkManager getInstance(@NonNull Context context) {
return WorkManagerImpl.getInstance(context);
}
然后又調用了WorkManager
的子類WorkManagerImpl.getInstance()
方法去初始化。
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static @NonNull WorkManagerImpl getInstance(@NonNull Context context) {
synchronized (sLock) {
WorkManagerImpl instance = getInstance();
if (instance == null) {
Context appContext = context.getApplicationContext();
if (appContext instanceof Configuration.Provider) {
//初始化
initialize(
appContext,
((Configuration.Provider) appContext).getWorkManagerConfiguration());
instance = getInstance(appContext);
} else {
throw new IllegalStateException("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.");
}
}
return instance;
}
}
WorkManagerImpl.getInstance()
又調用了WorkManagerImpl.initialize()
去實例化WorkManagerImpl
初斑。
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
synchronized (sLock) {
if (sDelegatedInstance != null && sDefaultInstance != null) {
throw new IllegalStateException("WorkManager is already initialized. Did you "
+ "try to initialize it manually without disabling "
+ "WorkManagerInitializer? See "
+ "WorkManager#initialize(Context, Configuration) or the class level "
+ "Javadoc for more information.");
}
if (sDelegatedInstance == null) {
context = context.getApplicationContext();
if (sDefaultInstance == null) {
sDefaultInstance = new WorkManagerImpl(
context,
configuration,
new WorkManagerTaskExecutor(configuration.getTaskExecutor()));
}
sDelegatedInstance = sDefaultInstance;
}
}
}
但是這里并不是第一次初始化辛润。
反編譯或者直接用AndroidStudio打開APK,點開AndroidManifest.xml文件见秤,能看到引入WorkManager
之后生成了一個provider
砂竖,在這個InitializationProvider
中,有一個WorkManagerInitializer
鹃答。
<provider
android:name="androidx.startup.InitializationProvider"
android:exported="false"
android:authorities="cn.zhangmushui.workmanagersample.androidx-startup">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup" />
</provider>
進入WorkManagerInitializer
:
public final class WorkManagerInitializer implements Initializer<WorkManager> {
private static final String TAG = Logger.tagWithPrefix("WrkMgrInitializer");
@NonNull
@Override
public WorkManager create(@NonNull Context context) {
// Initialize WorkManager with the default configuration.
Logger.get().debug(TAG, "Initializing WorkManager with default configuration.");
//WorkManager的初始化工作
WorkManager.initialize(context, new Configuration.Builder().build());
return WorkManager.getInstance(context);
}
@NonNull
@Override
public List<Class<? extends androidx.startup.Initializer<?>>> dependencies() {
return Collections.emptyList();
}
}
然后調用了WorkManager.initialize()
乎澄。
public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
WorkManagerImpl.initialize(context, configuration);
}
WorkManager.initialize()
調用了WorkManagerImpl.initialize()
,真正的初始化工作就在這里進行测摔。最終和MainActivity
中調用WorkManager.getInstance(this)
一樣置济,走到了WorkManagerImpl.initialize()
。所以,AndroidManifest.xml中的provider
才是WorkManager
的第一次實例化浙于。
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
synchronized (sLock) {
if (sDelegatedInstance != null && sDefaultInstance != null) {
throw new IllegalStateException("WorkManager is already initialized. Did you "
+ "try to initialize it manually without disabling "
+ "WorkManagerInitializer? See "
+ "WorkManager#initialize(Context, Configuration) or the class level "
+ "Javadoc for more information.");
}
if (sDelegatedInstance == null) {
context = context.getApplicationContext();
if (sDefaultInstance == null) {
//實例化WorkManager
sDefaultInstance = new WorkManagerImpl(
context,
configuration,
//實例化WorkManagerTaskExecutor
new WorkManagerTaskExecutor(configuration.getTaskExecutor()));
}
sDelegatedInstance = sDefaultInstance;
}
}
}
WorkManager
初始化的時候會傳入一個默認Configuration
修噪,Configuration
中包含了任務調度器,任務執(zhí)行器等對象路媚。
在initialize
方法中黄琼,實例化了一個WorkManagerTaskExecutor
傳入WorkManagerImpl
的構造方法,用來執(zhí)行任務整慎。
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public WorkManagerImpl(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor) {
this(context,
configuration,
workTaskExecutor,
context.getResources().getBoolean(R.bool.workmanager_test_configuration));
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public WorkManagerImpl(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor,
boolean useTestDatabase) {
this(context,
configuration,
workTaskExecutor,
WorkDatabase.create(
context.getApplicationContext(),
workTaskExecutor.getBackgroundExecutor(),
useTestDatabase)
);
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public WorkManagerImpl(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor,
@NonNull WorkDatabase database) {
Context applicationContext = context.getApplicationContext();
Logger.setLogger(new Logger.LogcatLogger(configuration.getMinimumLoggingLevel()));
//創(chuàng)建調度器Scheduler
List<Scheduler> schedulers =
createSchedulers(applicationContext, configuration, workTaskExecutor);
//實例化處理器Processor脏款,處理器可以根據需要智能的去調度和執(zhí)行任務。
Processor processor = new Processor(
context,
configuration,
workTaskExecutor,
database,
schedulers);
//真正的初始化
internalInit(context, configuration, workTaskExecutor, database, schedulers, processor);
}
在最后一個調用的構造方法中裤园,首先創(chuàng)建了一個調度器Scheduler
用于任務調度:
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
public List<Scheduler> createSchedulers(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor taskExecutor) {
return Arrays.asList(
Schedulers.createBestAvailableBackgroundScheduler(context, this),
// Specify the task executor directly here as this happens before internalInit.
// GreedyScheduler creates ConstraintTrackers and controllers eagerly.
//貪婪調度器
new GreedyScheduler(context, configuration, taskExecutor, this));
}
接著實例化了一個Processor
撤师,處理器可以根據需要智能的去調度和執(zhí)行任務。
Processor processor = new Processor(
context,
configuration,
workTaskExecutor,
database,
schedulers);
最后調用internalInit
進行真正的初始化工作拧揽。
private void internalInit(@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor,
@NonNull WorkDatabase workDatabase,
@NonNull List<Scheduler> schedulers,
@NonNull Processor processor) {
context = context.getApplicationContext();
mContext = context;
mConfiguration = configuration;
mWorkTaskExecutor = workTaskExecutor;
mWorkDatabase = workDatabase;
mSchedulers = schedulers;
mProcessor = processor;
mPreferenceUtils = new PreferenceUtils(workDatabase);
mForceStopRunnableCompleted = false;
// Check for direct boot mode
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && context.isDeviceProtectedStorage()) {
throw new IllegalStateException("Cannot initialize WorkManager in direct boot mode");
}
// Checks for app force stops.
//檢查app強制停止
mWorkTaskExecutor.executeOnBackgroundThread(new ForceStopRunnable(context, this));
}
executeOnBackgroundThread
方法傳入了一個ForceStopRunnable
對象剃盾,在這里,檢查到app正在執(zhí)行任務的時候淤袜,發(fā)生了閃退崩潰退出了程序痒谴,或者手機關機,就會重試之前的任務铡羡。
在WorkManager
初始化的過程中积蔚,ForceStopRunnable
的run
方法中,會檢測app被強制停止運行之前是否還有未完成的任務烦周,如果有尽爆,會繼續(xù)執(zhí)行。
@Override
public void run() {
try {
if (!multiProcessChecks()) {
return;
}
while (true) {
// Migrate the database to the no-backup directory if necessary.
WorkDatabasePathHelper.migrateDatabase(mContext);
// Clean invalid jobs attributed to WorkManager, and Workers that might have been
// interrupted because the application crashed (RUNNING state).
Logger.get().debug(TAG, "Performing cleanup operations.");
try {
forceStopRunnable();
break;
} catch (SQLiteCantOpenDatabaseException
| SQLiteDatabaseCorruptException
| SQLiteDatabaseLockedException
| SQLiteTableLockedException
| SQLiteConstraintException
| SQLiteAccessPermException exception) {
mRetryCount++;
if (mRetryCount >= MAX_ATTEMPTS) {
// ForceStopRunnable is usually the first thing that accesses a database
// (or an app's internal data directory). This means that weird
// PackageManager bugs are attributed to ForceStopRunnable, which is
// unfortunate. This gives the developer a better error
// message.
String message = "The file system on the device is in a bad state. "
+ "WorkManager cannot access the app's internal data store.";
Logger.get().error(TAG, message, exception);
IllegalStateException throwable = new IllegalStateException(message,
exception);
InitializationExceptionHandler exceptionHandler =
mWorkManager.getConfiguration().getExceptionHandler();
if (exceptionHandler != null) {
Logger.get().debug(TAG,
"Routing exception to the specified exception handler",
throwable);
exceptionHandler.handleException(throwable);
break;
} else {
throw throwable;
}
} else {
long duration = mRetryCount * BACKOFF_DURATION_MS;
Logger.get()
.debug(TAG, String.format("Retrying after %s", duration),
exception);
sleep(mRetryCount * BACKOFF_DURATION_MS);
}
}
}
} finally {
mWorkManager.onForceStopRunnableCompleted();
}
}
WorkManager初始化過程總結:
- WorkManager的真正初始化是由ContentProvider提供的WorkManagerInitializer中執(zhí)行的读慎,最終的實現是在WorkManager的子類WorkManagerImpl中漱贱。
- 初始化的過程中實例化了Configuration、WorkManagerTaskExecutor夭委、WorkDatabase幅狮、GreedyScheduler、Processor闰靴。
- 會檢測APP發(fā)生強制退出之前是否有未完成的任務彪笼,如果有,會繼續(xù)執(zhí)行蚂且。
4.2 WorkManager無約束條件任務的執(zhí)行
在MainActivity
中配猫,調用了enqueue()
:
WorkManager.getInstance(this).enqueue()
進入WorkManager:
@NonNull
public final Operation enqueue(@NonNull WorkRequest workRequest) {
return enqueue(Collections.singletonList(workRequest));
}
調用WorkManager
的抽象方法enqueue
:
@NonNull
public abstract Operation enqueue(@NonNull List<? extends WorkRequest> requests);
該抽象方法在WorkManagerImpl
中實現:
public Operation enqueue(
@NonNull List<? extends WorkRequest> requests) {
// This error is not being propagated as part of the Operation, as we want the
// app to crash during development. Having no workRequests is always a developer error.
if (requests.isEmpty()) {
throw new IllegalArgumentException(
"enqueue needs at least one WorkRequest.");
}
return new WorkContinuationImpl(this, requests).enqueue();
}
實例化了一個WorkContinuationImpl
對象,然后調用WorkContinuationImpl
的enqueue
方法杏死。WorkContinuationImpl
繼承了WorkContinuation
:
public WorkContinuationImpl(
@NonNull WorkManagerImpl workManagerImpl,
@NonNull List<? extends WorkRequest> work) {
this(
workManagerImpl,
null,
ExistingWorkPolicy.KEEP,
work,
null);
}
WorkContinuation
保存了任務相關的一些信息:
public WorkContinuationImpl(@NonNull WorkManagerImpl workManagerImpl,
@Nullable String name,
@NonNull ExistingWorkPolicy existingWorkPolicy,
@NonNull List<? extends WorkRequest> work,
@Nullable List<WorkContinuationImpl> parents) {
mWorkManagerImpl = workManagerImpl;
mName = name;
mExistingWorkPolicy = existingWorkPolicy;
mWork = work;
mParents = parents;
mIds = new ArrayList<>(mWork.size());
mAllIds = new ArrayList<>();
if (parents != null) {
for (WorkContinuationImpl parent : parents) {
mAllIds.addAll(parent.mAllIds);
}
}
for (int i = 0; i < work.size(); i++) {
String id = work.get(i).getStringId();
mIds.add(id);
mAllIds.add(id);
}
}
在WorkContinuationImpl
的enqueue
方法中泵肄,WorkManagerImpl
中的TaskExecutor
執(zhí)行了EnqueueRunnable
:
@Override
public @NonNull Operation enqueue() {
// Only enqueue if not already enqueued.
if (!mEnqueued) {
// The runnable walks the hierarchy of the continuations
// and marks them enqueued using the markEnqueued() method, parent first.
EnqueueRunnable runnable = new EnqueueRunnable(this);
//TaskExecutor執(zhí)行EnqueueRunnable
mWorkManagerImpl.getWorkTaskExecutor().executeOnBackgroundThread(runnable);
mOperation = runnable.getOperation();
} else {
Logger.get().warning(TAG,
String.format("Already enqueued work ids (%s)", TextUtils.join(", ", mIds)));
}
return mOperation;
}
EnqueueRunnable
中的run()
方法如下所示捆交,調用了scheduleWorkInBackground()
,這是后臺執(zhí)行任務的核心方法:
@Override
public void run() {
try {
if (mWorkContinuation.hasCycles()) {
throw new IllegalStateException(
String.format("WorkContinuation has cycles (%s)", mWorkContinuation));
}
boolean needsScheduling = addToDatabase();
if (needsScheduling) {
// Enable RescheduleReceiver, only when there are Worker's that need scheduling.
final Context context =
mWorkContinuation.getWorkManagerImpl().getApplicationContext();
PackageManagerHelper.setComponentEnabled(context, RescheduleReceiver.class, true);
//在后臺執(zhí)行任務
scheduleWorkInBackground();
}
mOperation.setState(Operation.SUCCESS);
} catch (Throwable exception) {
mOperation.setState(new Operation.State.FAILURE(exception));
}
}
scheduleWorkInBackground()
方法如下所示:
@VisibleForTesting
public void scheduleWorkInBackground() {
WorkManagerImpl workManager = mWorkContinuation.getWorkManagerImpl();
//調用Schedulers.schedule()腐巢,傳入了Configuration品追、WorkDatabase、Scheduler
Schedulers.schedule(
workManager.getConfiguration(),
workManager.getWorkDatabase(),
workManager.getSchedulers());
}
調用Schedulers.schedule()
冯丙,傳入了Configuration
肉瓦、WorkDatabase
、Scheduler
:
public static void schedule(
...
if (eligibleWorkSpecsForLimitedSlots != null
&& eligibleWorkSpecsForLimitedSlots.size() > 0) {
WorkSpec[] eligibleWorkSpecsArray =
new WorkSpec[eligibleWorkSpecsForLimitedSlots.size()];
eligibleWorkSpecsArray =
eligibleWorkSpecsForLimitedSlots.toArray(eligibleWorkSpecsArray);
//遍歷每個任務進行處理胃惜,由于這里執(zhí)行的是沒有限制條件的任務
//所以最終調用的是貪婪調度器GreedyScheduler的schedule方法
for (Scheduler scheduler : schedulers) {
if (scheduler.hasLimitedSchedulingSlots()) {
scheduler.schedule(eligibleWorkSpecsArray);
}
}
}
...
}
遍歷每個任務去執(zhí)行泞莉,沒有約束條件的任務最終是調用了貪婪調度器GreedyScheduler.schedule()
執(zhí)行:
@Override
public void schedule(@NonNull WorkSpec... workSpecs) {
...
Set<WorkSpec> constrainedWorkSpecs = new HashSet<>();
Set<String> constrainedWorkSpecIds = new HashSet<>();
for (WorkSpec workSpec : workSpecs) {
long nextRunTime = workSpec.calculateNextRunTime();
long now = System.currentTimeMillis();
if (workSpec.state == WorkInfo.State.ENQUEUED) {
if (now < nextRunTime) {
// Future work
if (mDelayedWorkTracker != null) {
mDelayedWorkTracker.schedule(workSpec);
}
} else if (workSpec.hasConstraints()) {
if (SDK_INT >= 23 && workSpec.constraints.requiresDeviceIdle()) {
// Ignore requests that have an idle mode constraint.
Logger.get().debug(TAG,
String.format("Ignoring WorkSpec %s, Requires device idle.",
workSpec));
} else if (SDK_INT >= 24 && workSpec.constraints.hasContentUriTriggers()) {
// Ignore requests that have content uri triggers.
Logger.get().debug(TAG,
String.format("Ignoring WorkSpec %s, Requires ContentUri triggers.",
workSpec));
} else {
constrainedWorkSpecs.add(workSpec);
constrainedWorkSpecIds.add(workSpec.id);
}
} else {
Logger.get().debug(TAG, String.format("Starting work for %s", workSpec.id));
//無約束條件會直接走這里
mWorkManagerImpl.startWork(workSpec.id);
}
}
}
...
}
沒有約束條件,直接走到了WorkManagerImpl.startWork()
:
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void startWork(@NonNull String workSpecId) {
startWork(workSpecId, null);
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void startWork(
@NonNull String workSpecId,
@Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
mWorkTaskExecutor
.executeOnBackgroundThread(
new StartWorkRunnable(this, workSpecId, runtimeExtras));
}
進入StartWorkRunnable
中:
@Override
public void run() {
//使用Processor去執(zhí)行任務
mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras);
}
這里使用Processor
去執(zhí)行任務船殉,調用了Processor.startWork()
:
public boolean startWork(
@NonNull String id,
@Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
WorkerWrapper workWrapper;
synchronized (mLock) {
...
//創(chuàng)建了一個WorkerWrapper鲫趁,WorkerWrapper是Runnable的包裝類
workWrapper =
new WorkerWrapper.Builder(
mAppContext,
mConfiguration,
mWorkTaskExecutor,
this,
mWorkDatabase,
id)
.withSchedulers(mSchedulers)
.withRuntimeExtras(runtimeExtras)
.build();
ListenableFuture<Boolean> future = workWrapper.getFuture();
future.addListener(
new FutureListener(this, id, future),
mWorkTaskExecutor.getMainThreadExecutor());
mEnqueuedWorkMap.put(id, workWrapper);
}
//WorkerWrapper交給WorkTaskExecutor去處理
mWorkTaskExecutor.getBackgroundExecutor().execute(workWrapper);
Logger.get().debug(TAG, String.format("%s: processing %s", getClass().getSimpleName(), id));
return true;
}
進入WorkerWrapper
的run
方法:
public void run() {
mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
mWorkDescription = createWorkDescription(mTags);
runWorker();
}
接著調用了WorkerWrapper
的runWorker()
方法:
private void runWorker() {
...
if (trySetRunning()) {
if (tryCheckForInterruptionAndResolve()) {
return;
}
final SettableFuture<ListenableWorker.Result> future = SettableFuture.create();
final WorkForegroundRunnable foregroundRunnable =
new WorkForegroundRunnable(
mAppContext,
mWorkSpec,
mWorker,
params.getForegroundUpdater(),
mWorkTaskExecutor
);
mWorkTaskExecutor.getMainThreadExecutor().execute(foregroundRunnable);
final ListenableFuture<Void> runExpedited = foregroundRunnable.getFuture();
runExpedited.addListener(new Runnable() {
@Override
public void run() {
try {
runExpedited.get();
Logger.get().debug(TAG,
String.format("Starting work for %s", mWorkSpec.workerClassName));
//這里是開始任務的核心方法
mInnerFuture = mWorker.startWork();
future.setFuture(mInnerFuture);
} catch (Throwable e) {
future.setException(e);
}
}
}, mWorkTaskExecutor.getMainThreadExecutor());
}
...
}
調用mWorker.startWork()
來到了ListenableFuture
的startWork()
:
@MainThread
public abstract @NonNull ListenableFuture<Result> startWork();
具體實現在Worker
類中:
public abstract class Worker extends ListenableWorker {
SettableFuture<Result> mFuture;
@Keep
@SuppressLint("BanKeepAnnotation")
public Worker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@WorkerThread
public abstract @NonNull Result doWork();
@Override
public final @NonNull ListenableFuture<Result> startWork() {
mFuture = SettableFuture.create();
getBackgroundExecutor().execute(new Runnable() {
@Override
public void run() {
try {
Result result = doWork();
mFuture.set(result);
} catch (Throwable throwable) {
mFuture.setException(throwable);
}
}
});
return mFuture;
}
}
而我們自定義的SimpleWorker
等類,繼承的就是這個Worker
類利虫,這樣就完成了無約束條件任務的執(zhí)行挨厚。
class SimpleWorker(context: Context, workParams: WorkerParameters) :
Worker(context, workParams) {
companion object {
const val TAG = "---SimpleWorker"
}
override fun doWork(): Result {
Log.d(TAG, "doWork: work start...")
try {
Thread.sleep(3000)
} catch (e: IOException) {
e.printStackTrace()
return Result.failure()
} finally {
Log.d(TAG, "doWork: work end...")
}
return Result.success()
}
}
WorkManager無約束條件任務執(zhí)行總結:
- WorkManager執(zhí)行了enqueue()后,創(chuàng)建WorkContinuationImpl對象執(zhí)行
enqueue()方法糠惫。 - WorkContinuationImpl持有的EnqueueRunnable對象將任務添加到db疫剃,
并交給Schedulers去調度。 - Schedulers將任務交給每一個Scheduler去處理寞钥,GreedyScheduler會先處
理這個任務慌申。 - GreedyScheduler經過一系列判斷后陌选,調用WorkManager的startWork()方
法執(zhí)行這種一次性理郑,非延遲,無約束的任務咨油。 - WorkManager持有的StartWorkRunnable對象會將任務交給Processor去
處理您炉,執(zhí)行startWork()方法。 - Processor創(chuàng)建一個WorkerWrapper對象役电,由它去調用Worker的
startWork()方法赚爵。
4.3 WorkManager有約束條件任務的執(zhí)行
反編譯或者直接用AndroidStudio打開APK,點開AndroidManifest.xml文件法瑟,看到添加了多個receiver
冀膝,每個receiver
對應一個約束條件,比如網絡狀態(tài):
<receiver
android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$NetworkStateProxy"
android:enabled="false"
android:exported="false"
android:directBootAware="false">
<intent-filter>
<action
android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
點進去霎挟,來到了ConstraintProxy
窝剖,它繼承了BroadcastReceiver
,所以在網絡變化酥夭、低電量赐纱、低內存脊奋、充電的時候能接收到系統(tǒng)廣播,然后在onReceive
進行處理:
abstract class ConstraintProxy extends BroadcastReceiver {
private static final String TAG = Logger.tagWithPrefix("ConstraintProxy");
@Override
public void onReceive(Context context, Intent intent) {
Logger.get().debug(TAG, String.format("onReceive : %s", intent));
//創(chuàng)建并啟動服務
Intent constraintChangedIntent = CommandHandler.createConstraintsChangedIntent(context);
context.startService(constraintChangedIntent);
}
/**
* Proxy for Battery Not Low constraint
*/
public static class BatteryNotLowProxy extends ConstraintProxy {
}
/**
* Proxy for Battery Charging constraint
*/
public static class BatteryChargingProxy extends ConstraintProxy {
}
/**
* Proxy for Storage Not Low constraint
*/
public static class StorageNotLowProxy extends ConstraintProxy {
}
/**
* Proxy for Network State constraints
*/
public static class NetworkStateProxy extends ConstraintProxy {
}
/**
* Enables/Disables proxies based on constraints in {@link WorkSpec}s
*
* @param context {@link Context}
* @param workSpecs list of {@link WorkSpec}s to update proxies against
*/
static void updateAll(Context context, List<WorkSpec> workSpecs) {
boolean batteryNotLowProxyEnabled = false;
boolean batteryChargingProxyEnabled = false;
boolean storageNotLowProxyEnabled = false;
boolean networkStateProxyEnabled = false;
for (WorkSpec workSpec : workSpecs) {
Constraints constraints = workSpec.constraints;
batteryNotLowProxyEnabled |= constraints.requiresBatteryNotLow();
batteryChargingProxyEnabled |= constraints.requiresCharging();
storageNotLowProxyEnabled |= constraints.requiresStorageNotLow();
networkStateProxyEnabled |=
constraints.getRequiredNetworkType() != NOT_REQUIRED;
if (batteryNotLowProxyEnabled && batteryChargingProxyEnabled
&& storageNotLowProxyEnabled && networkStateProxyEnabled) {
break;
}
}
Intent updateProxyIntent =
ConstraintProxyUpdateReceiver.newConstraintProxyUpdateIntent(
context,
batteryNotLowProxyEnabled,
batteryChargingProxyEnabled,
storageNotLowProxyEnabled,
networkStateProxyEnabled);
// ConstraintProxies are being updated via a separate broadcast receiver.
// For more information on why we do this look at b/73549299
context.sendBroadcast(updateProxyIntent);
}
}
點擊進入CommandHandler.createConstraintsChangedIntent()
方法疙描,這里啟動了一個SystemAlarmService
服務:
static Intent createConstraintsChangedIntent(@NonNull Context context) {
Intent intent = new Intent(context, SystemAlarmService.class);
intent.setAction(ACTION_CONSTRAINTS_CHANGED);
return intent;
}
再進入SystemAlarmService
诚隙,啟動服務后,在onStartCommand
中調用SystemAlarmDispatcher.add()
:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (mIsShutdown) {
Logger.get().info(TAG,
"Re-initializing SystemAlarmDispatcher after a request to shut-down.");
// Destroy the old dispatcher to complete it's lifecycle.
mDispatcher.onDestroy();
// Create a new dispatcher to setup a new lifecycle.
initializeDispatcher();
// Set mIsShutdown to false, to correctly accept new commands.
mIsShutdown = false;
}
if (intent != null) {
//調用SystemAlarmDispatcher.add()
mDispatcher.add(intent, startId);
}
// If the service were to crash, we want all unacknowledged Intents to get redelivered.
return Service.START_REDELIVER_INTENT;
}
然后在SystemAlarmDispatcher
的add
方法中調用了processCommand()
:
@MainThread
public boolean add(@NonNull final Intent intent, final int startId) {
...
intent.putExtra(KEY_START_ID, startId);
synchronized (mIntents) {
boolean hasCommands = !mIntents.isEmpty();
mIntents.add(intent);
if (!hasCommands) {
//執(zhí)行命令
processCommand();
}
}
return true;
}
在SystemAlarmDispatcher.processCommand()
中起胰,調用了CommandHandler.onHandleIntent()
去處理Intent:
private void processCommand() {
assertMainThread();
PowerManager.WakeLock processCommandLock =
WakeLocks.newWakeLock(mContext, PROCESS_COMMAND_TAG);
try {
processCommandLock.acquire();
// Process commands on the background thread.
mWorkManager.getWorkTaskExecutor().executeOnBackgroundThread(new Runnable() {
@Override
public void run() {
synchronized (mIntents) {
mCurrentIntent = mIntents.get(0);
}
if (mCurrentIntent != null) {
final String action = mCurrentIntent.getAction();
final int startId = mCurrentIntent.getIntExtra(KEY_START_ID,
DEFAULT_START_ID);
...
final PowerManager.WakeLock wakeLock = WakeLocks.newWakeLock(
mContext,
String.format("%s (%s)", action, startId));
try {
...
wakeLock.acquire();
//這里是核心方法久又,去處理Intent
mCommandHandler.onHandleIntent(mCurrentIntent, startId,
SystemAlarmDispatcher.this);
} catch (Throwable throwable) {
...
} finally {
...
}
}
}
});
} finally {
processCommandLock.release();
}
}
CommandHandler.onHandleIntent()
會對約束條件的改變作出處理:
@WorkerThread
void onHandleIntent(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
String action = intent.getAction();
if (ACTION_CONSTRAINTS_CHANGED.equals(action)) {
//帶約束條件改變會走這里
handleConstraintsChanged(intent, startId, dispatcher);
} else if (ACTION_RESCHEDULE.equals(action)) {
handleReschedule(intent, startId, dispatcher);
} else {
Bundle extras = intent.getExtras();
if (!hasKeys(extras, KEY_WORKSPEC_ID)) {
Logger.get().error(TAG,
String.format("Invalid request for %s, requires %s.",
action,
KEY_WORKSPEC_ID));
} else {
if (ACTION_SCHEDULE_WORK.equals(action)) {
handleScheduleWorkIntent(intent, startId, dispatcher);
} else if (ACTION_DELAY_MET.equals(action)) {
handleDelayMet(intent, startId, dispatcher);
} else if (ACTION_STOP_WORK.equals(action)) {
handleStopWork(intent, dispatcher);
} else if (ACTION_EXECUTION_COMPLETED.equals(action)) {
handleExecutionCompleted(intent, startId);
} else {
Logger.get().warning(TAG, String.format("Ignoring intent %s", intent));
}
}
}
}
CommandHandler.handleConstraintsChanged()
方法中實例化了一個ConstraintsCommandHandler
,調用了ConstraintsCommandHandler.handleConstraintsChanged()
:
private void handleConstraintsChanged(
@NonNull Intent intent, int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
Logger.get().debug(TAG, String.format("Handling constraints changed %s", intent));
// Constraints changed command handler is synchronous. No cleanup
// is necessary.
ConstraintsCommandHandler changedCommandHandler =
new ConstraintsCommandHandler(mContext, startId, dispatcher);
changedCommandHandler.handleConstraintsChanged();
}
在handleConstraintsChanged()
中效五,創(chuàng)建了一個DelayMetIntent
交給AddRunnable籽孙,然后調用SystemAlarmDispatcher
發(fā)送出去:
@WorkerThread
void handleConstraintsChanged() {
...
for (WorkSpec workSpec : eligibleWorkSpecs) {
String workSpecId = workSpec.id;
//創(chuàng)建了一個DelayMetIntent,交給AddRunnable火俄,然后SystemAlarmDispatcher發(fā)送出去
Intent intent = CommandHandler.createDelayMetIntent(mContext, workSpecId);
Logger.get().debug(TAG, String.format(
"Creating a delay_met command for workSpec with id (%s)", workSpecId));
mDispatcher.postOnMainThread(
new SystemAlarmDispatcher.AddRunnable(mDispatcher, intent, mStartId));
}
...
}
然后AddRunnable
的run
方法中犯建,又調用了SystemAlarmDispatcher.add()
:
static class AddRunnable implements Runnable {
private final SystemAlarmDispatcher mDispatcher;
private final Intent mIntent;
private final int mStartId;
AddRunnable(@NonNull SystemAlarmDispatcher dispatcher,
@NonNull Intent intent,
int startId) {
mDispatcher = dispatcher;
mIntent = intent;
mStartId = startId;
}
@Override
public void run() {
mDispatcher.add(mIntent, mStartId);
}
}
SystemAlarmDispatcher.add()
中執(zhí)行processCommand()
,然后又到了CommandHandler.onHandleIntent()
瓜客,而由于這次的Intent是DelayMetIntent
适瓦,所以這次走的是handleDelayMet
:
@WorkerThread
void onHandleIntent(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
String action = intent.getAction();
if (ACTION_CONSTRAINTS_CHANGED.equals(action)) {
handleConstraintsChanged(intent, startId, dispatcher);
} else if (ACTION_RESCHEDULE.equals(action)) {
handleReschedule(intent, startId, dispatcher);
} else {
Bundle extras = intent.getExtras();
if (!hasKeys(extras, KEY_WORKSPEC_ID)) {
Logger.get().error(TAG,
String.format("Invalid request for %s, requires %s.",
action,
KEY_WORKSPEC_ID));
} else {
if (ACTION_SCHEDULE_WORK.equals(action)) {
handleScheduleWorkIntent(intent, startId, dispatcher);
} else if (ACTION_DELAY_MET.equals(action)) {
//這一次,會走到這里
handleDelayMet(intent, startId, dispatcher);
} else if (ACTION_STOP_WORK.equals(action)) {
handleStopWork(intent, dispatcher);
} else if (ACTION_EXECUTION_COMPLETED.equals(action)) {
handleExecutionCompleted(intent, startId);
} else {
Logger.get().warning(TAG, String.format("Ignoring intent %s", intent));
}
}
}
}
在CommandHandler.handleDelayMet()
中谱仪,實例化DelayMetCommandHandler
:
private void handleDelayMet(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
Bundle extras = intent.getExtras();
synchronized (mLock) {
String workSpecId = extras.getString(KEY_WORKSPEC_ID);
Logger.get().debug(TAG, String.format("Handing delay met for %s", workSpecId));
// Check to see if we are already handling an ACTION_DELAY_MET for the WorkSpec.
// If we are, then there is nothing for us to do.
if (!mPendingDelayMet.containsKey(workSpecId)) {
DelayMetCommandHandler delayMetCommandHandler =
new DelayMetCommandHandler(mContext, startId, workSpecId, dispatcher);
mPendingDelayMet.put(workSpecId, delayMetCommandHandler);
delayMetCommandHandler.handleProcessWork();
} else {
Logger.get().debug(TAG,
String.format("WorkSpec %s is already being handled for ACTION_DELAY_MET",
workSpecId));
}
}
}
在DelayMetCommandHandler
中玻熙,會執(zhí)行onAllConstraintsMet
方法,onAllConstraintsMet
中會從SystemAlarmDispatcher
中獲取Processor
去開始執(zhí)行任務疯攒。后續(xù)邏輯就和4.2中StartWorkRunnable
中的邏輯一樣了嗦随。
@Override
public void onAllConstraintsMet(@NonNull List<String> workSpecIds) {
...
synchronized (mLock) {
if (mCurrentState == STATE_INITIAL) {
mCurrentState = STATE_START_REQUESTED;
//通過SystemAlarmDispatcher獲取Processor,調用startWork
boolean isEnqueued = mDispatcher.getProcessor().startWork(mWorkSpecId);
...
} else {
Logger.get().debug(TAG, String.format("Already started work for %s", mWorkSpecId));
}
}
}
關注木水小站 (zhangmushui.cn)和微信公眾號【木水Code】敬尺,及時獲取更多最新技術干貨枚尼。