WorkManager的介绍
WorkManager API 是一个适合用来替换所有先前的 Android 后台调度 API(包括 FirebaseJobDispatcher、GcmNetworkManager和 JobScheduler的组件
WorkManager 底层作业调度服务的逻辑
WorkManager的优点
-
工作约束
使用约束明确定义工作运行的最佳条件(例如,仅在设备采用 Wi-Fi 网络连接时、当设备处于空闲状态或者有足够的存储空间时运行。)
-
强大的调度
WorkManager 允许您使用灵活的调度窗口调度工作,以运行一次性或重复工作。您还可以对工作进行标记或命名,以便调度唯一的、可替换的工作以及监控或取消工作组。已调度的工作存储在内部托管的 SQLite 数据库中,由 WorkManager 负责确保该工作持续进行,并在设备重新启动后重新调度。此外,WorkManager 遵循低电耗模式等省电功能和最佳做法
-
灵活的重试政策
有时工作会失败。WorkManager 提供了灵活的重试政策,包括可配置的指数退避政策。
-
工作链
对于复杂的相关工作,您可以使用流畅自然的接口将各个工作任务串联起来,这样您便可以控制哪些部分依序运行,哪些部分并行运行。
对于每项工作任务,您可以定义工作的输入和输出数据。将工作串联在一起时,WorkManager 会自动将输出数据从一个工作任务传递给下一个工作任务
-
内置线程互操作性
WorkManager 无缝集成RxJava 和协程,并可灵活地插入您自己的异步 API。
使用入门
添加依赖
implementation 'androidx.work:work-runtime-ktx:2.7.1'
简单
定义任务
class UploadWorker(appContext:Context,workerParams:WorkerParameters): Worker(appContext,workerParams) {
override fun doWork(): Result {
uploadImages()
return Result.success() //工作完成
}
/**
* 上传图片
*/
private fun uploadImages() {
}
}
提交任务
binding?.clickBtn?.setOnClickListener {
Log.d("MainActivity","按钮点击事件")
val uploadWorkerRequest=OneTimeWorkRequestBuilder<UploadWorker>().build()
//将任务提交给WorkManager
WorkManager.getInstance(this).enqueue(uploadWorkerRequest)
}
有数据交换
定义任务
class ChangeDataWorker(val appContext: Context, val workerParams: WorkerParameters): Worker(appContext,workerParams){
override fun doWork(): Result {
//接收传递过来的数据
val data = workerParams.inputData.getString("Data")
Log.d("ChangeDataWorker","data:$data")
//将数据返回出去
var returnData=Data.Builder().putString("returnData","doWork").build()
return Result.success(returnData)
}
}
提交任务
binding?.clickBtn?.setOnClickListener {
Log.d("MainActivity","按钮点击事件")
var data= Data.Builder().putString("Data","给workmanager传递数据").build()
val changeDataWorker=OneTimeWorkRequestBuilder<ChangeDataWorker>()
.setInputData(data)
.build()
//想接收任务回馈的数据,需要状态机 livedata
WorkManager.getInstance(this).getWorkInfoByIdLiveData(changeDataWorker.id)
.observe(this,
{
Log.d("MainActivity","状态:${it.state.name}")
if(it.state.isFinished){
Log.d("MainActivity","回传的数据:${it.outputData.getString("returnData")}")
Log.d("MainActivity","状态:isFinished = true 后台任务完成")
}
})
//将任务提交给WorkManager
WorkManager.getInstance(this).enqueue(changeDataWorker)
}
多任务(单任务)
binding?.clickBtn?.setOnClickListener {
Log.d("MainActivity","按钮点击事件")
var task1=OneTimeWorkRequestBuilder<TaskWorker1>().build()
var task2=OneTimeWorkRequestBuilder<TaskWorker2>().build()
var task3=OneTimeWorkRequestBuilder<TaskWorker3>().build()
//第一种 按顺序执行 task1 task2 task3
WorkManager.getInstance(this)
.beginWith(task1)
.then(task2)
.then(task3)
.enqueue()
//第二种
var list= mutableListOf<OneTimeWorkRequest>()
list.add(task1)
list.add(task2)
// 先执行task1 task2 最后执行task3
WorkManager.getInstance(this).beginWith(list)
.then(task3).enqueue()
}
重复执行任务
binding?.clickBtn?.setOnClickListener {
// google规定,重复执行的任务时间间隔必须大于等于15分钟,如果你设置的时间小于15分钟会按照15分钟执行
var periodicWorkRequest=PeriodicWorkRequestBuilder<ChangeDataWorker>(10,TimeUnit.SECONDS).build()
//监听状态
WorkManager.getInstance(this).getWorkInfoByIdLiveData(periodicWorkRequest.id)
.observe(this,{
//轮询任务的状态一直是ENQUEUE
Log.d("MainActivty","状态:${it.state.name}")
})
WorkManager.getInstance(this).enqueue(periodicWorkRequest)
}
约束条件
binding?.clickBtn?.setOnClickListener {
//约束条件
var constraints=Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)// 网络连接中
.setRequiresCharging(true) // 充电中
.setRequiresDeviceIdle(true) //空闲时
.build()
var request=OneTimeWorkRequestBuilder<UploadWorker>()
.setConstraints(constraints)
.build()
//加入队列
WorkManager.getInstance(this).enqueue(request)
}
源码分析
初始化
WorkManager.getInstance(this)
进入getInstance方法
public static @NonNull WorkManager getInstance(@NonNull Context context) {
return WorkManagerImpl.getInstance(context);
}
进入WorkManagerImpl类的getInstance(context)方法
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static @NonNull WorkManagerImpl getInstance(@NonNull Context context) {
synchronized (sLock) {
WorkManagerImpl instance = getInstance();
//在APK清单文件中执行第一次,这个是第二次执行
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;
}
}
第二次执行只是为了拿到WorkManager的实现类
查看清单文件
进入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.initialize(context, new Configuration.Builder().build());
return WorkManager.getInstance(context);
}
}
进入initialize方法
public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
WorkManagerImpl.initialize(context, configuration);
}
进入WorkManagerImpl类的initialize方法
@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;
}
}
}
最终会进入WorkManagerImpl这个构造函数
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()));
List<Scheduler> schedulers =
createSchedulers(applicationContext, configuration, workTaskExecutor);
Processor processor = new Processor(
context,
configuration,
workTaskExecutor,
database,
schedulers);
internalInit(context, configuration, workTaskExecutor, database, schedulers, processor);
}
调用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;//room数据库
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.
mWorkTaskExecutor.executeOnBackgroundThread(new ForceStopRunnable(context, this));
}
第一次初始化做的事情:
- 初始化room数据库来保存任务(持久性保存)
- 初始化GreedyScheduler(贪婪执行器)
- 初始化配置信息
加入队列执行
public final Operation enqueue(@NonNull WorkRequest workRequest) {
return enqueue(Collections.singletonList(workRequest));
}
enqueue是一个抽象方法
public abstract Operation enqueue(@NonNull List<? extends WorkRequest> requests);
进入实现类WorkManagerImpl的enqueue方法
@Override
@NonNull
public Operation enqueue(
@NonNull List<? extends WorkRequest> requests) {
if (requests.isEmpty()) {
throw new IllegalArgumentException(
"enqueue needs at least one WorkRequest.");
}
return new WorkContinuationImpl(this, requests).enqueue();
}
进入WorkContinuationImpl类的enqueue方法
@Override
public @NonNull Operation enqueue() {
if (!mEnqueued) {
EnqueueRunnable runnable = new EnqueueRunnable(this);
//将任务放入线程池
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方法
public void run() {
try {
if (mWorkContinuation.hasCycles()) {
throw new IllegalStateException(
String.format("WorkContinuation has cycles (%s)", mWorkContinuation));
}
//建立数据库
boolean needsScheduling = addToDatabase();
if (needsScheduling) {
final Context context =
mWorkContinuation.getWorkManagerImpl().getApplicationContext();
PackageManagerHelper.setComponentEnabled(context, RescheduleReceiver.class, true);
scheduleWorkInBackground();
}
mOperation.setState(Operation.SUCCESS);
} catch (Throwable exception) {
mOperation.setState(new Operation.State.FAILURE(exception));
}
}
进入addToDatabase方法,建立数据库
public boolean addToDatabase() {
WorkManagerImpl workManagerImpl = mWorkContinuation.getWorkManagerImpl();
WorkDatabase workDatabase = workManagerImpl.getWorkDatabase();
workDatabase.beginTransaction();
try {
boolean needsScheduling = processContinuation(mWorkContinuation);
workDatabase.setTransactionSuccessful();
return needsScheduling;
} finally {
workDatabase.endTransaction();
}
}
进入scheduleWorkInBackground方法执行调度
public void scheduleWorkInBackground() {
WorkManagerImpl workManager = mWorkContinuation.getWorkManagerImpl();
//执行调度
Schedulers.schedule(
workManager.getConfiguration(),
workManager.getWorkDatabase(),
workManager.getSchedulers());
}
进入Schedulers类的schedule方法
public static void schedule(
@NonNull Configuration configuration,
@NonNull WorkDatabase workDatabase,
List<Scheduler> schedulers) {
if (schedulers == null || schedulers.size() == 0) {
return;
}
WorkSpecDao workSpecDao = workDatabase.workSpecDao();
List<WorkSpec> eligibleWorkSpecsForLimitedSlots;
List<WorkSpec> allEligibleWorkSpecs;
//开启事务(将任务更新到数据库中)
workDatabase.beginTransaction();
try {
eligibleWorkSpecsForLimitedSlots = workSpecDao.getEligibleWorkForScheduling(
configuration.getMaxSchedulerLimit());
allEligibleWorkSpecs = workSpecDao.getAllEligibleWorkSpecsForScheduling(
MAX_GREEDY_SCHEDULER_LIMIT);
if (eligibleWorkSpecsForLimitedSlots != null
&& eligibleWorkSpecsForLimitedSlots.size() > 0) {
long now = System.currentTimeMillis();
for (WorkSpec workSpec : eligibleWorkSpecsForLimitedSlots) {
workSpecDao.markWorkSpecScheduled(workSpec.id, now);
}
}
workDatabase.setTransactionSuccessful();
} finally {
workDatabase.endTransaction();
}
if (eligibleWorkSpecsForLimitedSlots != null
&& eligibleWorkSpecsForLimitedSlots.size() > 0) {
WorkSpec[] eligibleWorkSpecsArray =
new WorkSpec[eligibleWorkSpecsForLimitedSlots.size()];
eligibleWorkSpecsArray =
eligibleWorkSpecsForLimitedSlots.toArray(eligibleWorkSpecsArray);
for (Scheduler scheduler : schedulers) {
if (scheduler.hasLimitedSchedulingSlots()) {
scheduler.schedule(eligibleWorkSpecsArray);
}
}
}
if (allEligibleWorkSpecs != null && allEligibleWorkSpecs.size() > 0) {
WorkSpec[] enqueuedWorkSpecsArray = new WorkSpec[allEligibleWorkSpecs.size()];
enqueuedWorkSpecsArray = allEligibleWorkSpecs.toArray(enqueuedWorkSpecsArray);
for (Scheduler scheduler : schedulers) {
if (!scheduler.hasLimitedSchedulingSlots()) {
//执行任务
scheduler.schedule(enqueuedWorkSpecsArray);
}
}
}
}
scheduler是一个接口,我们进入他的实现类GreedyScheduler中
进入schedule方法中
public void schedule(@NonNull WorkSpec... workSpecs) {
if (mInDefaultProcess == null) {
checkDefaultProcess();
}
if (!mInDefaultProcess) {
Logger.get().info(TAG, "Ignoring schedule request in a secondary process");
return;
}
registerExecutionListenerIfNeeded();
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) {
if (mDelayedWorkTracker != null) {
mDelayedWorkTracker.schedule(workSpec);
}
} else if (workSpec.hasConstraints()) {//有约束条件
if (SDK_INT >= 23 && workSpec.constraints.requiresDeviceIdle()) {
Logger.get().debug(TAG,
String.format("Ignoring WorkSpec %s, Requires device idle.",
workSpec));
} else if (SDK_INT >= 24 && workSpec.constraints.hasContentUriTriggers()) {
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);
}
}
}
synchronized (mLock) {
if (!constrainedWorkSpecs.isEmpty()) {
Logger.get().debug(TAG, String.format("Starting tracking for [%s]",
TextUtils.join(",", constrainedWorkSpecIds)));
mConstrainedWorkSpecs.addAll(constrainedWorkSpecs);
mWorkConstraintsTracker.replace(mConstrainedWorkSpecs);
}
}
}
进入WorkManagerImpl类的startWork方法
public void startWork(@NonNull String workSpecId) {
startWork(workSpecId, null);
}
public void startWork(
@NonNull String workSpecId,
@Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
//将任务丢给线程池执行
mWorkTaskExecutor
.executeOnBackgroundThread(
new StartWorkRunnable(this, workSpecId, runtimeExtras));
}
进入StartWorkRunnable类,查看run方法
public void run() {
mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras);
}
进入Processor类中的startWork方法
public boolean startWork(
@NonNull String id,
@Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
WorkerWrapper workWrapper;
synchronized (mLock) {
if (isEnqueued(id)) {
Logger.get().debug(
TAG,
String.format("Work %s is already enqueued for processing", id));
return false;
}
//包装任务
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);
}
//线程池执行包装过后的任务
mWorkTaskExecutor.getBackgroundExecutor().execute(workWrapper);
Logger.get().debug(TAG, String.format("%s: processing %s", getClass().getSimpleName(), id));
return true;
}
进入WorkerWrapper,查看run方法
@WorkerThread
@Override
public void run() {
mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
mWorkDescription = createWorkDescription(mTags);
runWorker();
}
private void runWorker() {
if (tryCheckForInterruptionAndResolve()) {
return;
}
mWorkDatabase.beginTransaction();
try {
mWorkSpec = mWorkSpecDao.getWorkSpec(mWorkSpecId);
if (mWorkSpec == null) {
Logger.get().error(
TAG,
String.format("Didn't find WorkSpec for id %s", mWorkSpecId));
resolve(false);
mWorkDatabase.setTransactionSuccessful();
return;
}
if (mWorkSpec.state != ENQUEUED) {
resolveIncorrectStatus();
mWorkDatabase.setTransactionSuccessful();
Logger.get().debug(TAG,
String.format("%s is not in ENQUEUED state. Nothing more to do.",
mWorkSpec.workerClassName));
return;
}
if (mWorkSpec.isPeriodic() || mWorkSpec.isBackedOff()) {
long now = System.currentTimeMillis();
boolean isFirstRun = mWorkSpec.periodStartTime == 0;
if (!isFirstRun && now < mWorkSpec.calculateNextRunTime()) {
Logger.get().debug(TAG,
String.format(
"Delaying execution for %s because it is being executed "
+ "before schedule.",
mWorkSpec.workerClassName));
resolve(true);
mWorkDatabase.setTransactionSuccessful();
return;
}
}
mWorkDatabase.setTransactionSuccessful();
} finally {
mWorkDatabase.endTransaction();
}
Data input;
if (mWorkSpec.isPeriodic()) {
input = mWorkSpec.input;
} else {
InputMergerFactory inputMergerFactory = mConfiguration.getInputMergerFactory();
String inputMergerClassName = mWorkSpec.inputMergerClassName;
InputMerger inputMerger =
inputMergerFactory.createInputMergerWithDefaultFallback(inputMergerClassName);
if (inputMerger == null) {
Logger.get().error(TAG, String.format("Could not create Input Merger %s",
mWorkSpec.inputMergerClassName));
setFailedAndResolve();
return;
}
List<Data> inputs = new ArrayList<>();
inputs.add(mWorkSpec.input);
inputs.addAll(mWorkSpecDao.getInputsFromPrerequisites(mWorkSpecId));
input = inputMerger.merge(inputs);
}
final WorkerParameters params = new WorkerParameters(
UUID.fromString(mWorkSpecId),
input,
mTags,
mRuntimeExtras,
mWorkSpec.runAttemptCount,
mConfiguration.getExecutor(),
mWorkTaskExecutor,
mConfiguration.getWorkerFactory(),
new WorkProgressUpdater(mWorkDatabase, mWorkTaskExecutor),
new WorkForegroundUpdater(mWorkDatabase, mForegroundProcessor, mWorkTaskExecutor));
if (mWorker == null) {
mWorker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
mAppContext,
mWorkSpec.workerClassName,
params);
}
if (mWorker == null) {
Logger.get().error(TAG,
String.format("Could not create Worker %s", mWorkSpec.workerClassName));
setFailedAndResolve();
return;
}
if (mWorker.isUsed()) {
Logger.get().error(TAG,
String.format("Received an already-used Worker %s; WorkerFactory should return "
+ "new instances",
mWorkSpec.workerClassName));
setFailedAndResolve();
return;
}
mWorker.setUsed();
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());
final String workDescription = mWorkDescription;
future.addListener(new Runnable() {
@Override
@SuppressLint("SyntheticAccessor")
public void run() {
try {
ListenableWorker.Result result = future.get();
if (result == null) {
Logger.get().error(TAG, String.format(
"%s returned a null result. Treating it as a failure.",
mWorkSpec.workerClassName));
} else {
Logger.get().debug(TAG, String.format("%s returned a %s result.",
mWorkSpec.workerClassName, result));
mResult = result;
}
} catch (CancellationException exception) {
Logger.get().info(TAG, String.format("%s was cancelled", workDescription),
exception);
} catch (InterruptedException | ExecutionException exception) {
Logger.get().error(TAG,
String.format("%s failed because it threw an exception/error",
workDescription), exception);
} finally {
onWorkFinished();
}
}
}, mWorkTaskExecutor.getBackgroundExecutor());
} else {
resolveIncorrectStatus();
}
}
startWork是一个抽象类里面的方法
public abstract @NonNull ListenableFuture<Result> startWork();
进入worker这个类的startWork方法
@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;
}
@WorkerThread
public abstract @NonNull Result doWork();
doWork是一个抽象方法,实现在我们自定义的任务里面。
约束的分析
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));
Intent constraintChangedIntent = CommandHandler.createConstraintsChangedIntent(context);
context.startService(constraintChangedIntent);
}
}
采用广播监听的形式接收变化,同时开启一个系统的服务
CommandHandler.createConstraintsChangedIntent 是创建一个系统的闹钟服务
static Intent createConstraintsChangedIntent(@NonNull Context context) {
Intent intent = new Intent(context, SystemAlarmService.class);
intent.setAction(ACTION_CONSTRAINTS_CHANGED);
return intent;
}
进入SystemAlarmService类中
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.");
mDispatcher.onDestroy();
initializeDispatcher();
mIsShutdown = false;
}
if (intent != null) {
mDispatcher.add(intent, startId);
}
return Service.START_REDELIVER_INTENT;
}
进入SystemAlarmDispatcher类的add方法
public boolean add(@NonNull final Intent intent, final int startId) {
Logger.get().debug(TAG, String.format("Adding command %s (%s)", intent, startId));
assertMainThread();
String action = intent.getAction();
if (TextUtils.isEmpty(action)) {
Logger.get().warning(TAG, "Unknown command. Ignoring");
return false;
}
if (CommandHandler.ACTION_CONSTRAINTS_CHANGED.equals(action)
&& hasIntentWithAction(CommandHandler.ACTION_CONSTRAINTS_CHANGED)) {
return false;
}
intent.putExtra(KEY_START_ID, startId);
synchronized (mIntents) {
boolean hasCommands = !mIntents.isEmpty();
mIntents.add(intent);
if (!hasCommands)
//执行命令
processCommand();
}
}
return true;
}
进入processCommand方法
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);
Logger.get().debug(TAG,
String.format("Processing command %s, %s", mCurrentIntent,
startId));
//电量
final PowerManager.WakeLock wakeLock = WakeLocks.newWakeLock(
mContext,
String.format("%s (%s)", action, startId));
try {
Logger.get().debug(TAG, String.format(
"Acquiring operation wake lock (%s) %s",
action,
wakeLock));
wakeLock.acquire();
mCommandHandler.onHandleIntent(mCurrentIntent, startId,
SystemAlarmDispatcher.this);
} catch (Throwable throwable) {
Logger.get().error(
TAG,
"Unexpected error in onHandleIntent",
throwable);
} finally {
Logger.get().debug(
TAG,
String.format(
"Releasing operation wake lock (%s) %s",
action,
wakeLock));
wakeLock.release();
postOnMainThread(
new DequeueAndCheckForCompletion(SystemAlarmDispatcher.this));
}
}
}
});
} finally {
processCommandLock.release();
}
}
进入CommandHandler类的 onHandleIntent(mCurrentIntent, startId,SystemAlarmDispatcher.this)方法
void onHandleIntent(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
String action = intent.getAction();
//启动系统服务的是有一个标记就是ACTION_CONSTRAINTS_CHANGED
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));
}
}
}
}
进入handleConstraintsChanged方法
private void handleConstraintsChanged(
@NonNull Intent intent, int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
Logger.get().debug(TAG, String.format("Handling constraints changed %s", intent));
ConstraintsCommandHandler changedCommandHandler =
new ConstraintsCommandHandler(mContext, startId, dispatcher);
changedCommandHandler.handleConstraintsChanged();
}
进入ConstraintsCommandHandler类的handleConstraintsChanged方法
void handleConstraintsChanged() {
List<WorkSpec> candidates = mDispatcher.getWorkManager().getWorkDatabase()
.workSpecDao()
.getScheduledWork();
ConstraintProxy.updateAll(mContext, candidates);
mWorkConstraintsTracker.replace(candidates);
List<WorkSpec> eligibleWorkSpecs = new ArrayList<>(candidates.size());
long now = System.currentTimeMillis();
for (WorkSpec workSpec : candidates) {
String workSpecId = workSpec.id;
long triggerAt = workSpec.calculateNextRunTime();
if (now >= triggerAt && (!workSpec.hasConstraints()
|| mWorkConstraintsTracker.areAllConstraintsMet(workSpecId))) {
eligibleWorkSpecs.add(workSpec);
}
}
for (WorkSpec workSpec : eligibleWorkSpecs) {
String workSpecId = workSpec.id;
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));
}
mWorkConstraintsTracker.reset();
}
createDelayMetIntent方法会换掉标记 ,新标记CTION_DELAY_MET
static Intent createDelayMetIntent(@NonNull Context context, @NonNull String workSpecId) {
Intent intent = new Intent(context, SystemAlarmService.class);
intent.setAction(ACTION_DELAY_MET);
intent.putExtra(KEY_WORKSPEC_ID, workSpecId);
return intent;
}
会进入handleDelayMet(intent, startId, dispatcher)这个方法中
void onHandleIntent(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
。。。
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));
}
。。。
}
进入handleDelayMet方法
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));
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));
}
}
}
进入handleProcessWork方法
void handleProcessWork() {
mWakeLock = WakeLocks.newWakeLock(
mContext,
String.format("%s (%s)", mWorkSpecId, mStartId));
Logger.get().debug(TAG,
String.format("Acquiring wakelock %s for WorkSpec %s", mWakeLock, mWorkSpecId));
mWakeLock.acquire();
WorkSpec workSpec = mDispatcher.getWorkManager()
.getWorkDatabase()
.workSpecDao()
.getWorkSpec(mWorkSpecId);
if (workSpec == null) {
stopWork();
return;
}
mHasConstraints = workSpec.hasConstraints();
if (!mHasConstraints) {
Logger.get().debug(TAG, String.format("No constraints for %s", mWorkSpecId));
onAllConstraintsMet(Collections.singletonList(mWorkSpecId));
} else {
mWorkConstraintsTracker.replace(Collections.singletonList(workSpec));
}
}
进入onAllConstraintsMet方法
public void onAllConstraintsMet(@NonNull List<String> workSpecIds) {
if (!workSpecIds.contains(mWorkSpecId)) {
return;
}
synchronized (mLock) {
if (mCurrentState == STATE_INITIAL) {
mCurrentState = STATE_START_REQUESTED;
Logger.get().debug(TAG, String.format("onAllConstraintsMet for %s", mWorkSpecId));
//和上面的装饰任务的衔接上,
boolean isEnqueued = mDispatcher.getProcessor().startWork(mWorkSpecId);
if (isEnqueued) {
mDispatcher.getWorkTimer()
.startTimer(mWorkSpecId, WORK_PROCESSING_TIME_IN_MS, this);
} else {
cleanUp();
}
} else {
Logger.get().debug(TAG, String.format("Already started work for %s", mWorkSpecId));
}
}
}
常见面试题
workmanager的使用场景
处理非及时任务。例如:每天同步一次app的日志信息到服务,类似这种需求,不是执行执行但是又保证会执行的非及时任务。
workmanager怎么保证,当我把app杀掉后,依然会执行
记录的所有信息保存在数据库中,而不是内存中,持久性的保存记录,所以当app被杀掉之后,依然可以获取到需要执行的任务信息。
workmanager是怎么保证任务一定执行
Android操作系统会在系统级别服务中,来判定用户的约束条件,当约束条件满足时就会执行任务,但是触发检测采用的是广播的形式。