AsyncTask源码浅析

Posted 加冰雪碧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AsyncTask源码浅析相关的知识,希望对你有一定的参考价值。

在开发的过程中我们如果想进行一些耗时的操作不能直接在UI线程中进行,除了使用Handler机制来进行异步消息处理,android还给我们提供了一个非常方便的类AsyncTask来进行异步操作,在这篇文章中只对AsyncTask的源码进行一下梳理,如果对AsyncTask的使用还不太熟悉的可以先看一下API的使用方法。

我们往往是定义一个类继承AsyncTask,然后创建出这个类的实例,而后调用execute方法来执行任务,我们就从这里入手来分析源码,首先是构造方法:

 /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() 
        mWorker = new WorkerRunnable<Params, Result>() 
            public Result call() throws Exception 
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            
        ;

        mFuture = new FutureTask<Result>(mWorker) 
            @Override
            protected void done() 
                try 
                    postResultIfNotInvoked(get());
                 catch (InterruptedException e) 
                    android.util.Log.w(LOG_TAG, e);
                 catch (ExecutionException e) 
                    throw new RuntimeException("An error occured while executing doInBackground()",
                            e.getCause());
                 catch (CancellationException e) 
                    postResultIfNotInvoked(null);
                
            
        ;
    

首先看一下代码的注释,告诉我们这个构造器必须在UI线程中进行调用,这个在后面会给出分析。构造方法很简单,分别对创建出了WorkerRunnable和FutureTask对象并将其保存起来。先看看WorkerRunnable是什么东西:

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> 
        Params[] mParams;
    

实现了Callable接口(可以简单的将Callable对象看做一个执行run方法时有返回值的Runnable对象,只不过在Callable中改名叫call方法),是一个抽象类,在构造函数中重写了call方法,暂时先不用考虑里面的逻辑,后面会进行分析。

再看FutureTask类,它的构造方法中接受了一个Callable参数,也就是我们刚刚创建出来的WorkerRunnable对象,看一下它的方法列表不难找到一个比较熟悉的方法,run方法,我们进入看一下:

public void run() 
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try 
            Callable<V> c = callable;
            if (c != null && state == NEW) 
                V result;
                boolean ran;
                try 
                    result = c.call();
                    ran = true;
                 catch (Throwable ex) 
                    result = null;
                    ran = false;
                    setException(ex);
                
                if (ran)
                    set(result);
            
         finally 
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        
    

只看一下关键的部分,在这个方法中调用了Callable对象的call方法。

构造函数已经简单的分析完了,现在来看一下我们经常调用的execute方法:

 public final AsyncTask<Params, Progress, Result> execute(Params... params) 
        return executeOnExecutor(sDefaultExecutor, params);
    

可以看到,它只是简单的调用了另一个方法,但是出现了一个没有见过的参数sDefaultExecutor,来看一下这个参数是什么:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

/**
     * An @link Executor that executes tasks one at a time in serial
     * order.  This serialization is global to a particular process.
     */
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

从注释中可以看出这是一个一次只能执行一个任务的线程池,并且这是一个在进程范围内公用的池,看一下它的定义:

private static class SerialExecutor implements Executor 
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) 
            mTasks.offer(new Runnable() 
                public void run() 
                    try 
                        r.run();
                     finally 
                        scheduleNext();
                    
                
            );
            if (mActive == null) 
                scheduleNext();
            
        

        protected synchronized void scheduleNext() 
            if ((mActive = mTasks.poll()) != null) 
                THREAD_POOL_EXECUTOR.execute(mActive);
            
        
    

代码不是很多,首先在线程池中维护了一个双端队列的实例,并且在线程池的execute方法中并没有执行传入的Runnable对象,而是将它用另一个新创建的Runnable对象包装起来放到队列的尾部。显然,在第一次调用execute方法的时候mActive对象一定是null,这个时候会调用scheduleNext方法将队列中的元素拿出来,并且使用THREAD_POOL_EXECUTOR来执行它,看一下THREAD_POOL_EXECUTOR的代码:

 /**
     * An @link Executor that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

只是创建了一个固定规格和模式的线程池,这里不是分析的重点就不去深入它了。在执行完成后可以看到无论如何都会执行到SerialExecutor中execute方法的finally语句中,在这里又调用了scheduleNext进行重复的工作。通过上面的分析也就不难理解注释中说明的一次只能执行一个任务,虽然没有继续分析,但是可以猜想出AsyncTask的任务是由SerialExecutor进行分配,并且由于它是static的,在同一个进程内所有的AsyncTask中的任务都会放入到这个类的队列中按顺序执行。

接着回到AsyncTask的execute方法中,调用了executeOnExecutor方法,进入看一下:

 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) 
        if (mStatus != Status.PENDING) 
            switch (mStatus) 
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            
        

        mStatus = Status.RUNNING;

        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    

在这里可以看到熟悉的onPreExecute方法被调用了,由于前面的注释中说过,AsyncTask类对象的创建必须是在主线程中执行的,所以onPreExecute方法的执行也是在主线程中的。而后将传入的参数赋给了mWorker对象中的数组,使用传入的线程池对mFuture进行执行,因为传入的参数是sDefaultExecutor,所以执行的逻辑跳转回了SerialExecutor的execute方法,而后在线程池中执行了mFuture的run方法。根据我们前面的分析它的run方法调用了mWorker的call方法,那么call方法是在哪里实现的呢,没错,在构造函数中:

 public Result call() throws Exception 
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            

在这里执行了doInBackground方法,这个方法应该很熟悉了,它是一个抽象的方法,也是每次都要求我们必须进行重写的。这里由于执行过程还是在线程池中进行的,所以避免了在UI线程中进行耗时操作。方法执行完成后将返回值作为参数传递给了postResult方法,进入看一下:

 private Result postResult(Result result) 
        @SuppressWarnings("unchecked")
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    

在这里面看到了很熟悉的代码,Handler机制,那么这个Handler是在哪创建的呢,

private static final InternalHandler sHandler = new InternalHandler();

private static class InternalHandler extends Handler 
        @SuppressWarnings("unchecked", "RawUseOfParameterizedType")
        @Override
        public void handleMessage(Message msg) 
            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
            switch (msg.what) 
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            
        
    

很显然Handler类是静态的,在类加载的时候就会初始化这个类,现在回过头再来想一下刚才提到的AsyncTask一定要在UI线程中加载的问题,如果不在UI线程中进行加载,那么Handler自然也就不在UI线程中,那么onProgressUpdate方法和onPostExecute方法中也就不能执行更新UI的操作了。

继续看postResult方法,很简单,就是给Handler发了一个消息并且传了一个参数,而Handler调用了AsyncTask的finish方法用到了这个参数,下面是finish方法:

 private void finish(Result result) 
        if (isCancelled()) 
            onCancelled(result);
         else 
            onPostExecute(result);
        
        mStatus = Status.FINISHED;
    

在任务被取消时调用onCancelled方法回调,不然就调用我们熟悉的onPostExecute方法。而在Handler的handleMessage中还有一个接收项,它回调了我们常用的onProgressUpdate方法,找一下这个标记(MESSAGE_POST_PROGRESS)是怎样传入的,不难找到publishProgress方法:

protected final void publishProgress(Progress... values) 
        if (!isCancelled()) 
            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        
    

这也正是我们在doInBackground中经常使用的。



以上是关于AsyncTask源码浅析的主要内容,如果未能解决你的问题,请参考以下文章

Android -- AsyncTask源码解析

安卓学习笔记之AsyncTask机制浅析

AsyncTask浅析

MyBatis源码浅析

MyBatis源码浅析

AsyncTask使用及源码分析