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 - 一个学渣 - 博客园

posted @ 2020-10-09 14:52  Robin132929  阅读(778)  评论(0编辑  收藏  举报