JobIntentService源码解析
JobIntentService源码解析
一、什么是JobIntentService
JobIntentService用于执行加入到队列中的任务,在 android O或更高版本上运行时,工作将通过 jobscheduler 作为作业分派。 在旧版本上运行时,它将使用 Context.startService
二、JobIntentService源码分析
先来看下基本使用示例:
public class SimpleJobIntentService extends JobIntentService {
/**
* Unique job ID for this service.
*/
static final int JOB_ID = 1000;
/**
* Convenience method for enqueuing work in to this service.
*/
static void enqueueWork(Context context, Intent work) {
enqueueWork(context, SimpleJobIntentService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(Intent intent) {
// We have received work to do. The system or framework is already
// holding a wake lock for us at this point, so we can just go.
Log.i("SimpleJobIntentService", "Executing work: " + intent);
String label = intent.getStringExtra("label");
if (label == null) {
label = intent.toString();
}
toast("Executing: " + label);
for (int i = 0; i < 5; i++) {
Log.i("SimpleJobIntentService", "Running service " + (i + 1)
+ "/5 @ " + SystemClock.elapsedRealtime());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
Log.i("SimpleJobIntentService", "Completed service @ " + SystemClock.elapsedRealtime());
}
@Override
public void onDestroy() {
super.onDestroy();
toast("All work complete");
}
final Handler mHandler = new Handler();
// Helper for showing tests
void toast(final CharSequence text) {
mHandler.post(new Runnable() {
@Override public void run() {
Toast.makeText(SimpleJobIntentService.this, text, Toast.LENGTH_SHORT).show();
}
});
}
}
上面是Google提供的JobIntentService使用示例。
基本流程是继承JobIntentService重写onHandleWork方法,并在该方法内部处理收到的任务。任务的提交则是在enqueueWork中。
接下来我们来看下JobIntentService的源码,我们从enqueueWork开始
public static void enqueueWork(@NonNull Context context, @NonNull Class cls, int jobId,
@NonNull Intent work) {
enqueueWork(context, new ComponentName(context, cls), jobId, work);//注意此处构造的ComponentName传入的class是JobIntentService.class 后面会用到
}
public static void enqueueWork(@NonNull Context context, @NonNull ComponentName component,
int jobId, @NonNull Intent work) {
if (work == null) {
throw new IllegalArgumentException("work must not be null");
}
synchronized (sLock) {
WorkEnqueuer we = getWorkEnqueuer(context, component, true, jobId);
we.ensureJobId(jobId);
we.enqueueWork(work);
}
}
static WorkEnqueuer getWorkEnqueuer(Context context, ComponentName cn, boolean hasJobId,
int jobId) {
WorkEnqueuer we = sClassWorkEnqueuer.get(cn);
if (we == null) {
if (Build.VERSION.SDK_INT >= 26) {//根据不同的版本号构造不同的实现类
if (!hasJobId) {
throw new IllegalArgumentException("Can't be here without a job id");
}
we = new JobWorkEnqueuer(context, cn, jobId);
} else {
we = new CompatWorkEnqueuer(context, cn);
}
sClassWorkEnqueuer.put(cn, we);
}
return we;
}
enqueueWork内部经过调用最终通过getWorkEnqueuer来获取一个WorkEnqueuer类型实例并调用了WorkEnqueuer的enqueueWork把intent作为参数传入。getWorkEnqueuer内部会根据系统版本的不同构造不同的WorkEnqueuer,简单来说就是Android 8.0以及上返回的是JobWorkEnqueuer实例,Android 8.0之前版本返回CompatWorkEnqueuer实例。JobWorkEnqueuer和CompatWorkEnqueuer都是WorkEnqueuer的实现类。
WorkEnqueuer到底是干嘛的呢,一起来看下
abstract static class WorkEnqueuer {
final ComponentName mComponentName;
boolean mHasJobId;
int mJobId;
WorkEnqueuer(Context context, ComponentName cn) {
mComponentName = cn;
}
void ensureJobId(int jobId) {
if (!mHasJobId) {
mHasJobId = true;
mJobId = jobId;
} else if (mJobId != jobId) {
throw new IllegalArgumentException("Given job ID " + jobId
+ " is different than previous " + mJobId);
}
}
abstract void enqueueWork(Intent work);
public void serviceStartReceived() {
}
public void serviceProcessingStarted() {
}
public void serviceProcessingFinished() {
}
}
WorkEnqueuer是JobIntentService的一个内部抽象类,其主要作用类似一个任务分发的中转站,因为JobIntentService针对不同Android版本最后执行的操作不同,所以我们需要把启动时传入的任务交给WorkEnqueuer,WorkEnqueuer收到任务后根据不同Android版本构造不同的实现类去处理这些任务。
从getWorkEnqueuer开始之后的流程大多是根据系统版本分为两个分支即Android 8.0以及上、Android 8.0之前版本。所以我们分别来看下这两个不同分支的流程。
Android O之前版本
getWorkEnqueuer返回的是CompatWorkEnqueuer类型实例。
CompatWorkEnqueuer是用来处理Android 8.0以下版本的任务。
static final class CompatWorkEnqueuer extends WorkEnqueuer {
private final Context mContext;
private final PowerManager.WakeLock mLaunchWakeLock;
private final PowerManager.WakeLock mRunWakeLock;
boolean mLaunchingService;
boolean mServiceProcessing;
CompatWorkEnqueuer(Context context, ComponentName cn) {
super(context, cn);
mContext = context.getApplicationContext();
// Make wake locks. We need two, because the launch wake lock wants to have
// a timeout, and the system does not do the right thing if you mix timeout and
// non timeout (or even changing the timeout duration) in one wake lock.
//此处需要注意的是因为需要唤醒锁 所以使用JobIntentService
需要android.Manifest.permission.WAKE_LOCK权限
PowerManager pm = ((PowerManager) context.getSystemService(Context.POWER_SERVICE));
mLaunchWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
cn.getClassName() + ":launch");
mLaunchWakeLock.setReferenceCounted(false);
mRunWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
cn.getClassName() + ":run");
mRunWakeLock.setReferenceCounted(false);
}
@Override
void enqueueWork(Intent work) {
Intent intent = new Intent(work);
intent.setComponent(mComponentName);
if (DEBUG) Log.d(TAG, "Starting service for work: " + work);
if (mContext.startService(intent) != null) {//调用startService来处理
synchronized (this) {
if (!mLaunchingService) {
mLaunchingService = true;
if (!mServiceProcessing) {
// If the service is not already holding the wake lock for
// itself, acquire it now to keep the system running until
// we get this work dispatched. We use a timeout here to
// protect against whatever problem may cause it to not get
// the work.
mLaunchWakeLock.acquire(60 * 1000); }
}
}
}
}
@Override
public void serviceStartReceived() {
synchronized (this) {
// Once we have started processing work, we can count whatever last
// enqueueWork() that happened as handled.
mLaunchingService = false;
}
}
@Override
public void serviceProcessingStarted() {
synchronized (this) {
// We hold the wake lock as long as the service is processing commands.
if (!mServiceProcessing) {
mServiceProcessing = true;
// Keep the device awake, but only for at most 10 minutes at a time
// (Similar to JobScheduler.)
mRunWakeLock.acquire(10 * 60 * 1000L);
mLaunchWakeLock.release();
}
}
}
@Override
public void serviceProcessingFinished() {
synchronized (this) {
if (mServiceProcessing) {
// If we are transitioning back to a wakelock with a timeout, do the same
// as if we had enqueued work without the service running.
if (mLaunchingService) {
mLaunchWakeLock.acquire(60 * 1000);
}
mServiceProcessing = false;
mRunWakeLock.release();
}
}
}
}
CompatWorkEnqueuer中我们主要关注下其enqueueWork
函数。在该函数内部调用了startService来启动一个service,这里这个service就是JobIntentService,因为传入的intent中的ComponentName是JobIntentService,这个Component的构造是在上面的JobIntentService的enqueueWork函数中完成的。
void enqueueWork(Intent work) {
Intent intent = new Intent(work);
intent.setComponent(mComponentName);
if (DEBUG) Log.d(TAG, "Starting service for work: " + work);
if (mContext.startService(intent) != null) {//1 调用是startService启动JobIntentService
synchronized (this) {
if (!mLaunchingService) {
mLaunchingService = true;
if (!mServiceProcessing) {
// If the service is not already holding the wake lock for
// itself, acquire it now to keep the system running until
// we get this work dispatched. We use a timeout here to
// protect against whatever problem may cause it to not get
// the work.
mLaunchWakeLock.acquire(60 * 1000);
}
}
}
}
}
JobIntentService继承自service,JobIntentService启动会先调用构造函数,看下其构造函数
public JobIntentService() {
if (Build.VERSION.SDK_INT >= 26) {
mCompatQueue = null;
} else {
mCompatQueue = new ArrayList<>();
}
}
mCompatQueue是一个CompatWorkItem list,用来存储当前的CompatWorkItem。CompatWorkItem继承自GenericWorkItem
,GenericWorkItem是描述一个正在分发的任务的抽象,GenericWorkItem有两个实现类CompatWorkItem和WrapperWorkItem。
interface GenericWorkItem {
Intent getIntent();
void complete();
}
CompatWorkItem适用于Android O之前的版本,主要是从service的onStartCommand函数中接收intent。
Android O之前版本在JobIntentService构造函数中为mCompatQueue进行赋值。
接下来我们看下其onCreate函数
public void onCreate() {
super.onCreate();
if (DEBUG) Log.d(TAG, "CREATING: " + this);
if (Build.VERSION.SDK_INT >= 26) {
//...
} else {
mJobImpl = null;
ComponentName cn = new ComponentName(this, this.getClass());
mCompatWorkEnqueuer = getWorkEnqueuer(this, cn, false, 0);
}
}
可以看到是通过getWorkEnqueuer获取一个WorkEnqueuer并赋值给mCompatWorkEnqueuer。因为之前已经通过getWorkEnqueuer创建的CompatWorkEnqueuer实例此处会返回已经创建的CompatWorkEnqueuer实例。
之后service启动根据生命周期会调用onStartCommand。
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
if (mCompatQueue != null) {//1 判断mCompatQueue 是否为空
mCompatWorkEnqueuer.serviceStartReceived();
if (DEBUG) Log.d(TAG, "Received compat start command #" + startId + ": " + intent);
synchronized (mCompatQueue) {
mCompatQueue.add(new CompatWorkItem(intent != null ? intent : new Intent(),
startId));//2 构造CompatWorkItem存到mCompatQueue
ensureProcessorRunningLocked(true);//3 调用ensureProcessorRunningLocked
}
return START_REDELIVER_INTENT;
} else {
if (DEBUG) Log.d(TAG, "Ignoring start command: " + intent);
return START_NOT_STICKY;
}
}
onStartCommand会判断mCompatQueue 是否为空,我们知道mCompatQueue 已经在构造函数中赋值了是非空的。然后会把当前的intent等信息封装进CompatWorkItem并存到mCompatQueue中。之后调用了ensureProcessorRunningLocked。
CommandProcessor mCurProcessor;
void ensureProcessorRunningLocked(boolean reportStarted) {
if (mCurProcessor == null) {//1 判空
mCurProcessor = new CommandProcessor();//2 构造CommandProcessor
if (mCompatWorkEnqueuer != null && reportStarted) {
mCompatWorkEnqueuer.serviceProcessingStarted();
}
if (DEBUG) Log.d(TAG, "Starting processor: " + mCurProcessor);
mCurProcessor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);//3 执行mCurProcessor
}
}
在ensureProcessorRunningLocked中首先会判断mCurProcessor是否为空,因为之前并未给mCurProcessor赋值所以此处是为空的。然后会构造CommandProcessor实例并给mCurProcessor赋值。之后就是执行mCurProcessor。
我们来看下 CommandProcessor,CommandProcessor继承自AsyncTask,在上面的ensureProcessorRunningLocked函数中会在最后启动这个AsyncTask,然后其最终会走到doInBackground函数中(这个涉及AsyncTask的相关知识 有兴趣的可以自行查找相关资料 此处不再展开)。在其doInBackground函数中调用了onHandleWork。还记得我们之前的使用示例代码么我们是在onHandleWork处理任务的。
final class CommandProcessor extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
GenericWorkItem work;
if (DEBUG) Log.d(TAG, "Starting to dequeue work...");
while ((work = dequeueWork()) != null) {
if (DEBUG) Log.d(TAG, "Processing next work: " + work);
onHandleWork(work.getIntent());
if (DEBUG) Log.d(TAG, "Completing work: " + work);
work.complete();
}
if (DEBUG) Log.d(TAG, "Done processing work!");
return null;
}
@Override
protected void onCancelled(Void aVoid) {
processorFinished();
}
@Override
protected void onPostExecute(Void aVoid) {
processorFinished();
}
}
至此Android O之前版本(8.0之前版本)的流程就分析完了。
Android O以及之后的版本
在最开始的getWorkEnqueuer中如果是Android O以及之后的版本会构造JobWorkEnqueuer实例并返回。
static WorkEnqueuer getWorkEnqueuer(Context context, ComponentName cn, boolean hasJobId,
int jobId) {
WorkEnqueuer we = sClassWorkEnqueuer.get(cn);
if (we == null) {
if (Build.VERSION.SDK_INT >= 26) {
if (!hasJobId) {
throw new IllegalArgumentException("Can't be here without a job id");
}
we = new JobWorkEnqueuer(context, cn, jobId);//构造JobWorkEnqueuer实例
} else {
//...
}
sClassWorkEnqueuer.put(cn, we);
}
return we;
}
然后调用了JobWorkEnqueuer的enqueueWork方法。
JobWorkEnqueuer是用来处理Android 8.0及以上版本的任务分发。其enqueueWork的操作是调用JobScheduler.enqueue启动JobIntentService
。
static final class JobWorkEnqueuer extends JobIntentService.WorkEnqueuer {
private final JobInfo mJobInfo;
private final JobScheduler mJobScheduler;
JobWorkEnqueuer(Context context, ComponentName cn, int jobId) {
super(context, cn);
ensureJobId(jobId);
JobInfo.Builder b = new JobInfo.Builder(jobId, mComponentName);//构造JobInfo 此处传入的ComponentName是JobIntentService.class
mJobInfo = b.setOverrideDeadline(0).build();
mJobScheduler = (JobScheduler) context.getApplicationContext().getSystemService(
Context.JOB_SCHEDULER_SERVICE);
}
@Override
void enqueueWork(Intent work) {//enqueueWork的操作是调用JobScheduler.enqueue
if (DEBUG) Log.d(TAG, "Enqueueing work: " + work);
mJobScheduler.enqueue(mJobInfo, new JobWorkItem(work));
}
}
之后便是JobIntentService的启动流程。
构造函数中mCompatQueue 置空,onCreate中构造JobServiceEngineImpl实例并赋值给mJobImpl。
public JobIntentService() {
if (Build.VERSION.SDK_INT >= 26) {
mCompatQueue = null;
} else {
//...
}
}
public void onCreate() {
super.onCreate();
if (DEBUG) Log.d(TAG, "CREATING: " + this);
if (Build.VERSION.SDK_INT >= 26) {
mJobImpl = new JobServiceEngineImpl(this);
mCompatWorkEnqueuer = null;
} else {
//...
}
}
JobServiceEngineImpl继承自JobServiceEngine并实现了CompatJobEngine
接口
static final class JobServiceEngineImpl extends JobServiceEngine
implements JobIntentService.CompatJobEngine {
static final String TAG = "JobServiceEngineImpl";
static final boolean DEBUG = false;
final JobIntentService mService;
final Object mLock = new Object();
JobParameters mParams;
final class WrapperWorkItem implements JobIntentService.GenericWorkItem {
final JobWorkItem mJobWork;
WrapperWorkItem(JobWorkItem jobWork) {
mJobWork = jobWork;
}
@Override
public Intent getIntent() {
return mJobWork.getIntent();
}
@Override
public void complete() {
synchronized (mLock) {
if (mParams != null) {
mParams.completeWork(mJobWork);
}
}
}
}
JobServiceEngineImpl(JobIntentService service) {
super(service);
mService = service;
}
@Override
public IBinder compatGetBinder() {
return getBinder();
}
@Override
public boolean onStartJob(JobParameters params) {
if (DEBUG) Log.d(TAG, "onStartJob: " + params);
mParams = params;
// We can now start dequeuing work!
mService.ensureProcessorRunningLocked(false);
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
if (DEBUG) Log.d(TAG, "onStartJob: " + params);
boolean result = mService.doStopCurrentWork();
synchronized (mLock) {
// Once we return, the job is stopped, so its JobParameters are no
// longer valid and we should not be doing anything with them.
mParams = null;
}
return result;
}
/**
* Dequeue some work.
*/
@Override
public JobIntentService.GenericWorkItem dequeueWork() {
JobWorkItem work;
synchronized (mLock) {
if (mParams == null) {
return null;
}
work = mParams.dequeueWork();
}
if (work != null) {
work.getIntent().setExtrasClassLoader(mService.getClassLoader());
return new WrapperWorkItem(work);
} else {
return null;
}
}
}
之后就是JobService运行过程(感兴趣的看去可以JobService使用解析 此处不再展开)最终会走到JobServiceEngineImpl的onStartJob方法。
public boolean onStartJob(JobParameters params) {
if (DEBUG) Log.d(TAG, "onStartJob: " + params);
mParams = params;
// We can now start dequeuing work!
mService.ensureProcessorRunningLocked(false);
return true;
}
onStartJob调用 mService.ensureProcessorRunningLocked即JobIntentService中的ensureProcessorRunningLocked,在Android 0之前版本流程分析中我们已经说明过,之后的流程跟Android 0之前版本流程是一样的。
JobIntentService详解及使用_Houson_c的博客-CSDN博客
JobIntentService - 一个学渣 - 博客园