相关文章系列
- jetpack组件——入门篇
- jetpack系列——lifecycle源码分析
- jetpack系列—LiveData源码分析和实现事件分发总线
- jetpack系列——ViewModel源码分析
- 数据绑定技术DataBinding
- jetpack系列——DataBinding源码分析
- jectpack系列——paging源码分析
WorkManager的作用
- 确保有重要的后台任务,一定会被执行(例如:非及时性的上传、下载,同步数据等)
- 内部对电量进行了优化,不需要我们去处理电量优化
- API14到最新版本,都可以使用WorkManager来管理后台任务
- WorkManager不能做保活操作
- 调度,管理,执行的后台任务的常见,通常是可延迟的后台任务
def work_version = "2.3.4"
// Kotlin + coroutines
implementation "androidx.work:work-runtime-ktx:$work_version"
// optional - GCMNetworkManager support
implementation "androidx.work:work-gcm:$work_version"
// optional - Test helpers
androidTestImplementation "androidx.work:work-testing:$work_version"
class MyWork(@NonNull context: Context, @NonNull workerParams: WorkerParameters)
: Worker(context, workerParams) {
override fun doWork(): Result {
val value = inputData.getString("in_key")
Log.e("TAG", "value = $value")
Log.e("TAG", "开始睡眠")
Thread.sleep(3000)
Log.e("TAG", "结束睡眠")
return Result.success(workDataOf("out_key" to "$value result"))
}
}
val constraints = Constraints.Builder()
//NetworkType.NOT_REQUIRED:对网络没有要求
//NetworkType.CONNECTED:网络的时候执行
//NetworkType.UNMETERED:不计费的网络比如Wi-Fi
//NetworkType.NOT_ROAMING:非漫游网络
//NetworkType.METERED:计费网络比如3g,4g下执行
//注意:不代表恢复网络,就立马执行
.setRequiredNetworkType(NetworkType.METERED)//👈设置条件为网络连接情况
.build()
val workReuest =
//PeriodicWorkRequest:周期性任务
OneTimeWorkRequestBuilder<MyWork>()//👈一次性任务
//.setConstraints(constraints)//👈设置条件
.setInputData(workDataOf("in_key" to "Peakmain"))//👈输入简单数据
.setInitialDelay(5L,TimeUnit.SECONDS)//设置5s延迟执行
.addTag("peakmain")
.build()
workManager.enqueue(workReuest)
//监听数据变化
workManager.getWorkInfoByIdLiveData(workReuest.id)
.observe(this, Observer {
Log.e("TAG", "onCreate:" + it.state)
if (it.state == WorkInfo.State.SUCCEEDED) {
Log.e("TAG", "onCreate" + it.outputData.getString("out_key"))
}
})
//取消任务
workManager.cancelWorkById(workRequest.getId());
- 任务链和任务组合
-
责任链
-
WorkManager.getInstance(this)
.beginWith(A)
.then(B).enqueue()
-
AB,CD先执行最后执行E
var workManager1: WorkContinuation=WorkManager.getInstance(this)
.beginWith(A)
.then(B).enqueue()
var workManager2: WorkContinuation=WorkManager.getInstance(this)
.beginWith(A)
.then(B).enqueue()
var takeList = ArrayList<WorkContinuation>()
takeList.add(workManager1)
takeList.add(workManager2)
var workManager: WorkContinuation = WorkContinuation.combine(takeList)
.then(E)
.enqeue()
源码分析
初始化操作getInstance源码分析
public static @NonNull WorkManager getInstance(@NonNull Context context) {
return WorkManagerImpl.getInstance(context);
}
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 的实现类
initialize源码分析
public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
synchronized (sLock) {
if (sDelegatedInstance != null && sDefaultInstance != null) {
//抛出异常
}
if (sDelegatedInstance == null) {
context = context.getApplicationContext();
if (sDefaultInstance == null) {
sDefaultInstance = new WorkManagerImpl(
context,
configuration,
new WorkManagerTaskExecutor(configuration.getTaskExecutor()));
}
sDelegatedInstance = sDefaultInstance;
}
}
}
- initialize目的是new WorkManagerImpl实例
public WorkManagerImpl(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor) {
this(context,
configuration,
workTaskExecutor,
context.getResources().getBoolean(R.bool.workmanager_test_configuration));
}
public WorkManagerImpl(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor,
boolean useTestDatabase) {
this(context,
configuration,
workTaskExecutor,
WorkDatabase.create(
context.getApplicationContext(),
workTaskExecutor.getBackgroundExecutor(),
useTestDatabase)//👈创建了Room数据库
);
}
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, workTaskExecutor);
Processor processor = new Processor(
context,
configuration,
workTaskExecutor,
database,
schedulers);
internalInit(context, configuration, workTaskExecutor, database, schedulers, processor);
}
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;
// Checks for app force stops.
mWorkTaskExecutor.executeOnBackgroundThread(new ForceStopRunnable(context, this));
}
- 创建数据库Room
- 创建任务池
- 创建Processor
- Checks for app force stops.检测被停止的事情(如:关机、死机等),百分百会执行ForceStopRunnable
- ForceStopRunnable目的是内部做容错处理,手机发送意外,内部必须知道
加入队列执行源码分析
public final Operation enqueue(@NonNull WorkRequest workRequest) {
return enqueue(Collections.singletonList(workRequest));
}
public abstract Operation enqueue(@NonNull List<? extends WorkRequest> requests);
上面分析,我们知道实现类是WorkManagerImpl,所以会调用WorkManagerImpl的enqueue方法
public Operation enqueue(
@NonNull List<? extends WorkRequest> workRequests) {
//代码省略
return new WorkContinuationImpl(this, workRequests).enqueue();
}
public @NonNull Operation enqueue() {
// Only enqueue if not already enqueued.
if (!mEnqueued) {
EnqueueRunnable runnable = new EnqueueRunnable(this);
mWorkManagerImpl.getWorkTaskExecutor().executeOnBackgroundThread(runnable);
mOperation = runnable.getOperation();
} else {
//代码省略
}
return mOperation;
}
public void run() {
try {
//代码省略
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);
scheduleWorkInBackground();
}
mOperation.setState(Operation.SUCCESS);
} catch (Throwable exception) {
mOperation.setState(new Operation.State.FAILURE(exception));
}
}
开始执行后台任务
public void scheduleWorkInBackground() {
WorkManagerImpl workManager = mWorkContinuation.getWorkManagerImpl();
Schedulers.schedule(
workManager.getConfiguration(),//👈配置
workManager.getWorkDatabase(),//👈数据库
workManager.getSchedulers());
}
public static void schedule(
@NonNull Configuration configuration,
@NonNull WorkDatabase workDatabase,
List<Scheduler> schedulers) {
//获得Room
WorkSpecDao workSpecDao = workDatabase.workSpecDao();
List<WorkSpec> eligibleWorkSpecs;
//开启事务
workDatabase.beginTransaction();
try {
eligibleWorkSpecs = workSpecDao.getEligibleWorkForScheduling(
configuration.getMaxSchedulerLimit());
if (eligibleWorkSpecs != null && eligibleWorkSpecs.size() > 0) {
long now = System.currentTimeMillis();
for (WorkSpec workSpec : eligibleWorkSpecs) {
workSpecDao.markWorkSpecScheduled(workSpec.id, now);
}
}
workDatabase.setTransactionSuccessful();
} finally {
workDatabase.endTransaction();
}
if (eligibleWorkSpecs != null && eligibleWorkSpecs.size() > 0) {
WorkSpec[] eligibleWorkSpecsArray = eligibleWorkSpecs.toArray(new WorkSpec[0]);
for (Scheduler scheduler : schedulers) {
scheduler.schedule(eligibleWorkSpecsArray);
}
}
}
void schedule(@NonNull WorkSpec... workSpecs);
我们会发现有5个实现类,我们看GreedyScheduler
public void schedule(@NonNull WorkSpec... workSpecs) {
//代码省略
registerExecutionListenerIfNeeded();
List<WorkSpec> constrainedWorkSpecs = new ArrayList<>();
List<String> constrainedWorkSpecIds = new ArrayList<>();
//遍历所有的任务
for (WorkSpec workSpec : workSpecs) {
if (workSpec.state == WorkInfo.State.ENQUEUED
&& !workSpec.isPeriodic()
&& workSpec.initialDelay == 0L
&& !workSpec.isBackedOff()) {
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()) {
// 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);
}
}
}
synchronized (mLock) {
if (!constrainedWorkSpecs.isEmpty()) {
mConstrainedWorkSpecs.addAll(constrainedWorkSpecs);
mWorkConstraintsTracker.replace(mConstrainedWorkSpecs);
}
}
}
一、当我们没有设置约束的时候,会走到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));
}
public void run() {
mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras);
}
public boolean startWork(
@NonNull String id,
@Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
WorkerWrapper workWrapper;
synchronized (mLock) {
//WorkerWrapper实际是个子线程
workWrapper =
new WorkerWrapper.Builder(
mAppContext,
mConfiguration,
mWorkTaskExecutor,
this,
mWorkDatabase,
id)
.withSchedulers(mSchedulers)
.withRuntimeExtras(runtimeExtras)
.build();
}
mWorkTaskExecutor.getBackgroundExecutor().execute(workWrapper);
Logger.get().debug(TAG, String.format("%s: processing %s", getClass().getSimpleName(), id));
return true;
}
public void run() {
mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
mWorkDescription = createWorkDescription(mTags);
runWorker();
}
private void runWorker() {
if (trySetRunning()) {
mWorkTaskExecutor.getMainThreadExecutor()
.execute(new Runnable() {
@Override
public void run() {
try {
mInnerFuture = mWorker.startWork();
future.setFuture(mInnerFuture);
} catch (Throwable e) {
future.setException(e);
}
}
});
}, mWorkTaskExecutor.getBackgroundExecutor());
}
//代码省略
}
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;
}
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);
}
}
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) {
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) {
mDispatcher.add(intent, startId);
}
return Service.START_REDELIVER_INTENT;
}
public boolean add(@NonNull final Intent intent, final int startId) {
String action = intent.getAction();
intent.putExtra(KEY_START_ID, startId);
synchronized (mIntents) {
boolean hasCommands = !mIntents.isEmpty();
mIntents.add(intent);
if (!hasCommands) {
processCommand();
}
}
return true;
}
private void processCommand() {
assertMainThread();
PowerManager.WakeLock processCommandLock =
WakeLocks.newWakeLock(mContext, PROCESS_COMMAND_TAG);
try {
processCommandLock.acquire();
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();
mCommandHandler.onHandleIntent(mCurrentIntent, startId,
SystemAlarmDispatcher.this);
} catch (Throwable throwable) {
} finally {
}
}
}
});
} finally {
processCommandLock.release();
}
}
void onHandleIntent(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
String action = intent.getAction();
if (ACTION_CONSTRAINTS_CHANGED.equals(action)) {
handleConstraintsChanged(intent, startId, dispatcher);
}
//代码省略
}
private void handleConstraintsChanged(
@NonNull Intent intent, int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
ConstraintsCommandHandler changedCommandHandler =
new ConstraintsCommandHandler(mContext, startId, dispatcher);
changedCommandHandler.handleConstraintsChanged();
}
//改变约束条件
void handleConstraintsChanged() {
//后的所有数据库的任务数据
List<WorkSpec> candidates = mDispatcher.getWorkManager().getWorkDatabase()
.workSpecDao()
.getScheduledWork();
ConstraintProxy.updateAll(mContext, candidates);
//遍历所有数据库的数据
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);
mDispatcher.postOnMainThread(
new SystemAlarmDispatcher.AddRunnable(mDispatcher, intent, mStartId));
}
mWorkConstraintsTracker.reset();
}
//修改约束条件
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;
}
此时又会走一遍SystemAlarmService的onStartCommand,最后会再次来到onHandleIntent方法
void onHandleIntent(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
String action = intent.getAction();
else if (ACTION_DELAY_MET.equals(action)) {
handleDelayMet(intent, startId, dispatcher);
}
}
}
}
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 {
}
}
}
void handleProcessWork() {
mWakeLock = WakeLocks.newWakeLock(
mContext,
String.format("%s (%s)", mWorkSpecId, mStartId));
mWakeLock.acquire();
WorkSpec workSpec = mDispatcher.getWorkManager()
.getWorkDatabase()
.workSpecDao()
.getWorkSpec(mWorkSpecId);
if (workSpec == null) {
stopWork();
return;
}
mHasConstraints = workSpec.hasConstraints();
if (!mHasConstraints) {
onAllConstraintsMet(Collections.singletonList(mWorkSpecId));
} else {
mWorkConstraintsTracker.replace(Collections.singletonList(workSpec));
}
}
public void onAllConstraintsMet(@NonNull List<String> workSpecIds) {
if (!workSpecIds.contains(mWorkSpecId)) {
return;
}
synchronized (mLock) {
if (mCurrentState == STATE_INITIAL) {
mCurrentState = STATE_START_REQUESTED;
boolean isEnqueued = mDispatcher.getProcessor().startWork(mWorkSpecId);
} else {
Logger.get().debug(TAG, String.format("Already started work for %s", mWorkSpecId));
}
}
}
public boolean startWork(@NonNull String id) {
return startWork(id, null);
}
我们发现回到了没有设置约束的时候