在之前的博客《Android中AsyncTask使用详解》中我们提到AsyncTask是对Thread和Handler的组合包装,本文将通过解析的方式让大家了解AsyncTask的工作原理。

AsyncTask的源码链接https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/AsyncTask.java

AsyncTask一开始定义了一些字段,如下所示:

private static final String LOG_TAG = "AsyncTask";    //CPU_COUNT为手机中的CPU核数    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();    //将手机中的CPU核数加1作为AsyncTask所使用的线程池的核心线程数的大小    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;    //将CPU_COUNT * 2 + 1作为AsyncTask所使用的线程池的最大线程数的大小    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;    private static final int KEEP_ALIVE = 1;    //实例化线程工厂ThreadFactory,sThreadFactory用于在后面创建线程池    private static final ThreadFactory sThreadFactory = new ThreadFactory() {        //mCount为AtomicInteger类型,AtomicInteger是一个提供原子操作的Integer类,        //确保了其getAndIncrement方法是线程安全的        private final AtomicInteger mCount = new AtomicInteger(1);        //重写newThread方法的目的是为了将新增线程的名字以"AsyncTask #"标识        public Thread newThread(Runnable r) {            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());        }    };    //实例化阻塞式队列BlockingQueue,队列中存放Runnable,容量为128    private static final BlockingQueue sPoolWorkQueue =            new LinkedBlockingQueue(128);    //根据上面定义的参数实例化线程池    public static final Executor THREAD_POOL_EXECUTOR            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

通过以上代码和注释我们可以知道,AsyncTask初始化了一些参数,并用这些参数实例化了一个线程池THREAD_POOL_EXECUTOR,需要注意的是该线程池被定义为public static final,由此我们可以看出AsyncTask内部维护了一个静态的线程池,默认情况下,AsyncTask的实际工作就是通过该THREAD_POOL_EXECUTOR完成的。

我们继续,在执行完上面的代码后,AsyncTask又有如下一条语句:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

上面的代码实例化了一个SerialExecutor类型的实例SERIAL_EXECUTOR,它也是public static final的。SerialExecutor是AsyncTask的一个内部类,代码如下所示:

//SerialExecutor实现了Executor接口中的execute方法,该类用于串行执行任务,    //即一个接一个地执行任务,而不是并行执行任务    private static class SerialExecutor implements Executor {        //mTasks是一个维护Runnable的双端队列,ArrayDeque没有容量限制,其容量可自增长        final ArrayDeque mTasks = new ArrayDeque();        //mActive表示当前正在执行的任务Runnable        Runnable mActive;        public synchronized void execute(final Runnable r) {            //execute方法会传入一个Runnable类型的变量r            //然后我们会实例化一个Runnable类型的匿名内部类以对r进行封装,            //通过队列的offer方法将封装后的Runnable添加到队尾            mTasks.offer(new Runnable() {                public void run() {                    try {                        //执行r的run方法,开始执行任务                        //此处r的run方法是在线程池中执行的                        r.run();                    } finally {                        //当任务执行完毕的时候,通过调用scheduleNext方法执行下一个Runnable任务                        scheduleNext();                    }                }            });            //只有当前没有执行任何任务时,才会立即执行scheduleNext方法            if (mActive == null) {                scheduleNext();            }        }        protected synchronized void scheduleNext() {            //通过mTasks的poll方法进行出队操作,删除并返回队头的Runnable,            //将返回的Runnable赋值给mActive,            //如果不为空,那么就让将其作为参数传递给THREAD_POOL_EXECUTOR的execute方法进行执行            if ((mActive = mTasks.poll()) != null) {                THREAD_POOL_EXECUTOR.execute(mActive);            }        }    }

通过以上代码和注释我们可以知道:

  • SerialExecutor实现了Executor接口中的execute方法,该类用于串行执行任务,即一个接一个地执行任务,而不是并行执行任务。

  • SerialExecutor内部维护了一个存放Runnable的双端队列mTasks。当执行SerialExecutor的execute方法时,会传入一个Runnable变量r,但是mTasks并不直接存储r,而是又新new了一个匿名Runnable对象,其内部会调用r,这样就对r进行了封装,将该封装后的Runnable对象通过队列的offer方法入队,添加到mTasks的队尾。

  • SerialExecutor内部通过mActive存储着当前正在执行的任务Runnable。当执行SerialExecutor的execute方法时,首先会向mTasks的队尾添加进一个Runnable。然后判断如果mActive为null,即当前没有任务Runnable正在运行,那么就会执行scheduleNext()方法。当执行scheduleNext方法的时候,会首先从mTasks中通过poll方法出队,删除并返回队头的Runnable,将返回的Runnable赋值给mActive,如果不为空,那么就让将其作为参数传递给THREAD_POOL_EXECUTOR的execute方法进行执行。由此,我们可以看出SerialExecutor实际上是通过之前定义的线程池THREAD_POOL_EXECUTOR进行实际的处理的。

  • 当将mTasks中的Runnable作为参数传递给THREAD_POOL_EXECUTOR执行execute方法时,会在线程池的工作线程中执行匿名内部类Runnable中的try-finally代码段,即先在工作线程中执行r.run()方法去执行任务,无论任务r正常完成还是抛出异常,都会在finally中执行scheduleNext方法,用于执行mTasks中的下一个任务。从而在此处我们可以看出SerialExecutor是一个接一个执行任务,是串行执行任务,而不是并行执行。

AsyncTask内部定义了一个Status枚举类型,如下所示:

public enum Status {        //PENDING表示还没有开始执行任务        PENDING,        //RUNNING表示已经开始执行任务        RUNNING,        //FINISHED表示任务已经执行完成或被取消了,总之onPostExecute方法已经被调用了        FINISHED,    }

一个AsyncTask正常情况下会经历PENDING->RUNNING->FINISHED三个状态。

AsyncTask还定义了以下字段:

//用于通过Handler发布result的Message Code    private static final int MESSAGE_POST_RESULT = 0x1;    //用于通过Handler发布progress的Message Code    private static final int MESSAGE_POST_PROGRESS = 0x2;    //sDefaultExecutor表示AsyncTask默认使用SERIAL_EXECUTOR作为Executor,    //即默认情况下AsyncTask是串行执行任务,而不是并行执行任务    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;    //InternalHandler是AsyncTask中定义的一个静态内部类,其绑定了主线程的Looper和消息队列    private static InternalHandler sHandler;    //mWorker是一个实现了Callable接口的对象,其实现了Callable接口的call方法    private final WorkerRunnable mWorker;    //根据mFuture是一个FutureTask对象,需要用mWorker作为参数实例化mFuture    private final FutureTask mFuture;    //AsyncTask的初始状态位PENDING    private volatile Status mStatus = Status.PENDING;    //mCancelled标识当前任务是否被取消了    private final AtomicBoolean mCancelled = new AtomicBoolean();    //mTaskInvoked标识当前任务是否真正开始执行了    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

我们对以上代码再进行一下说明:

  • sDefaultExecutor表示AsyncTask执行任务时默认所使用的线程池,sDefaultExecutor的初始值为SERIAL_EXECUTOR,表示默认情况下AsyncTask是串行执行任务,而不是并行执行任务。

  • InternalHandler是AsyncTask中定义的一个静态内部类,其部分源码如下所示:

    private static class InternalHandler extends Handler {    public InternalHandler() {        //Looper类的getMainLooper方法是个静态方法,该方法返回主线程的Looper        //此处用主线程的Looper初始化InternalHandler,表示InternalHandler绑定了主线程        super(Looper.getMainLooper());    }    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})    @Override    public void handleMessage(Message msg) {        AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;        switch (msg.what) {            case MESSAGE_POST_RESULT:                //发布最后结果                result.mTask.finish(result.mData[0]);                break;            case MESSAGE_POST_PROGRESS:                //发布阶段性处理结果                result.mTask.onProgressUpdate(result.mData);                break;        }    }}

    通过InternalHandler的构造函数我们可以发现,用主线程的Looper初始化了InternalHandler,说明InternalHandler绑定了主线程。后面会讨论InternalHandler的handleMessage方法。

  • 由于AsyncTask能够取消任务,所以AsyncTask使用了FutureTask以及与其相关的Callable,此处对二者简单进行一下介绍。FutureTask、Callable在Java的并发编程中是比较常见的,可以用来获取任务执行完之后的返回值,也可以取消线程池中的某个任务。Callable是一个接口,其内部定义了call方法,在call方法内需要编写代码执行具体的任务,在这一点上Callable接口与Runnable接口很类似,不过不同的是Runnable的run方法没有返回值,Callable的call方法可以指定返回值。FutureTask类同时实现了Callable接口和Runnable接口,FutureTask的构造函数中需要传入一个Callable对象以对其进行实例化。Executor的execute方法接收一个Runnable对象,由于FutureTask实现了Runnable接口,所以可以把一个FutureTask对象传递给Executor的execute方法去执行。当任务执行完毕的时候会执行FutureTask的done方法,我们可以在这个方法中写一些逻辑处理。在任务执行的过程中,我们也可以随时调用FutureTask的cancel方法取消执行任务,任务取消后也会执行FutureTask的done方法。我们也可以通过FutureTask的get方法阻塞式地等待任务的返回值(即Callable的call方法的返回值),如果任务执行完了就立即返回执行的结果,否则就阻塞式等待call方法的完成。

  • 我们上面对Callable和FutureTask的使用及其作用进行了简单介绍,我们再回到AsyncTask的代码中看一下。mFuture是FutureTask类型的对象,mWorker是WorkerRunnable类型的对象,WorkerRunnable是AsyncTask中的一个内部类,代码如下所示:

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

    由此可以看出WorkerRunnable其实就是一个指定了泛型Result的Callable,所以mWorker也就是一个Callable对象。后面会讲解mWorker和mFuture的实例化。

  • mStatus的值为PENDING,表示AsyncTask的初始状态为未执行状态。mCancelled标识当前任务是否被取消了,mTaskInvoked标识当前任务是否真正开始执行了。

下面我们看一下AsyncTask的构造函数:

//AsyncTask的构造函数需要在UI线程上调用public AsyncTask() {        //实例化mWorker,实现了Callable接口的call方法        mWorker = new WorkerRunnable() {            public Result call() throws Exception {                //call方法是在线程池的某个线程中执行的,而不是运行在主线程中                //call方法开始执行后,就将mTaskInvoked设置为true,表示任务开始执行                mTaskInvoked.set(true);                //将执行call方法的线程设置为后台线程级别                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //在线程池的工作线程中执行doInBackground方法,执行实际的任务,并返回结果                Result result = doInBackground(mParams);                Binder.flushPendingCommands();                //将执行完的结果传递给postResult方法                return postResult(result);            }        };        //用mWorker实例化mFuture        mFuture = new FutureTask(mWorker) {            @Override            protected void done() {                //任务执行完毕或取消任务都会执行done方法                try {                    postResultIfNotInvoked(get());                } catch (InterruptedException e) {                    android.util.Log.w(LOG_TAG, e);                } catch (ExecutionException e) {                    throw new RuntimeException("An error occurred while executing doInBackground()",                            e.getCause());                } catch (CancellationException e) {                    postResultIfNotInvoked(null);                }            }        };    }

在AsyncTask的构造函数中依次实例化了mWorker和mFuture,AsyncTask的构造函数需要在UI线程上调用。下面对以上代码进行一下说明。

  • mWorker
    我们之前提到,mWorker其实是一个Callable类型的对象。实例化mWorker,实现了Callable接口的call方法。call方法是在线程池的某个线程中执行的,而不是运行在主线程中。在线程池的工作线程中执行doInBackground方法,执行实际的任务,并返回结果。当doInBackground执行完毕后,将执行完的结果传递给postResult方法。postResult方法我们后面会再讲解。

  • mFuture
    mFuture是一个FutureTask类型的对象,用mWorker作为参数实例化了mFuture。在这里,其实现了FutureTask的done方法,我们之前提到,当FutureTask的任务执行完成或任务取消的时候会执行FutureTask的done方法。done方法里面的逻辑我们稍后再将。

在实例化了AsyncTask对象之后,我们就可以调用AsyncTask的execute方法执行任务,execute代码如下所示:

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

execute方法有@MainThread,所以该方法应该在主线程上执行。通过上面代码我们发现,execute方法只是简单调用了executeOnExecutor方法,并且把sDefaultExecutor作为参数传递给了executeOnExecutor,此处就能看出sDefaultExecutor是默认执行任务的Executor了。

我们再看一下executeOnExecutor方法,其代码如下所示:

@MainThread    public final AsyncTask executeOnExecutor(Executor exec,            Params... params) {        if (mStatus != Status.PENDING) {            switch (mStatus) {                case RUNNING:                    //如果当前AsyncTask已经处于运行状态,那么就抛出异常,不再执行新的任务                    throw new IllegalStateException("Cannot execute task:"                            + " the task is already running.");                case FINISHED:                    //如果当前AsyncTask已经把之前的任务运行完成,那么也抛出异常,不再执行新的任务                    throw new IllegalStateException("Cannot execute task:"                            + " the task has already been executed "                            + "(a task can be executed only once)");            }        }        //将AsyncTask的状态置为运行状态        mStatus = Status.RUNNING;        //在真正执行任务前,先调用onPreExecute方法        onPreExecute();        mWorker.mParams = params;        //Executor的execute方法接收Runnable参数,由于mFuture是FutureTask的实例,        //且FutureTask同时实现了Callable和Runnable接口,所以此处可以让exec执行mFuture        exec.execute(mFuture);        //最后将AsyncTask自身返回        return this;    }

下面对以上代码进行一下说明:

  • 一个AsyncTask实例执行执行一次任务,当第二次执行任务时就会抛出异常。executeOnExecutor方法一开始就检查AsyncTask的状态是不是PENDING,只有PENDING状态才往下执行,如果是其他状态表明现在正在执行另一个已有的任务或者已经执行完成了一个任务,这种情况下都会抛出异常。

  • 如果开始是PENDING状态,那么就说明该AsyncTask还没执行过任何任务,代码可以继续执行,然后将状态设置为RUNNING,表示开始执行任务。

  • 在真正执行任务前,先调用onPreExecute方法。由于executeOnExecutor方法应该运行在主线程上,所以此处的onPreExecute方法也会运行在主线程上,可以在该方法中做一些UI上的处理操作。

  • Executor的execute方法接收Runnable参数,由于mFuture是FutureTask的实例,且FutureTask同时实现了Callable和Runnable接口,所以此处可以让exec通过execute方法在执行mFuture。在执行了exec.execute(mFuture)之后,后面会在exec的工作线程中执行mWorker的call方法,我们之前在介绍mWorker的实例化的时候也介绍了call方法内部的执行过程,会首先在工作线程中执行doInBackground方法,并返回结果,然后将结果传递给postResult方法。

下面我们看一下postResult方法,代码如下所示:

private Result postResult(Result result) {        @SuppressWarnings("unchecked")        //通过getHandler获取InternalHandler,InternalHandler绑定主线程        //根据InternalHandler创建一个Message Code为MESSAGE_POST_RESULT的Message        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult(this, result));        //将该message发送给InternalHandler        message.sendToTarget();        return result;    }

在postResult方法中,通过getHandler获取InternalHandler,InternalHandler绑定主线程。getHandler代码如下所示:

private static Handler getHandler() {        synchronized (AsyncTask.class) {            if (sHandler == null) {                sHandler = new InternalHandler();            }            return sHandler;        }    }

在得到InternalHandler对象之后,会根据InternalHandler创建一个Message Code为MESSAGE_POST_RESULT的Message,此处还将doInBackground返回的result通过new AsyncTaskResult(this, result)封装成了AsyncTaskResult,将其作为message的obj属性。

AsyncTaskResult是AsyncTask的一个内部类,其代码如下所示:

//AsyncTaskResult用于发布result或用于发布阶段性的数据    @SuppressWarnings({"RawUseOfParameterizedType"})    private static class AsyncTaskResult {        //mTask表示当前AsyncTaskResult是哪个AsyncTask的结果        final AsyncTask mTask;        //mData表示其存储的数据        final Data[] mData;        AsyncTaskResult(AsyncTask task, Data... data) {            //此处的data是可变数组            mTask = task;            mData = data;        }    }

在构建了message对象后,通过message.sendToTarget()将该message发送给InternalHandler,之后InternalHandler的handleMessage方法会接收并处理该message,如下所示:

public void handleMessage(Message msg) {            //msg.obj是AsyncTaskResult类型            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;            switch (msg.what) {                case MESSAGE_POST_RESULT:                    //发布最后结果                    result.mTask.finish(result.mData[0]);                    break;                ...                    result.mTask.onProgressUpdate(result.mData);                    break;            }        }

msg.obj是AsyncTaskResult类型,result.mTask表示当前AsyncTaskResult所绑定的AsyncTask。result.mData[0]表示的是doInBackground所返回的处理结果。将该结果传递给AsyncTask的finish方法,finish代码如下所示:

private void finish(Result result) {        if (isCancelled()) {            //如果任务被取消了,那么执行onCancelled方法            onCancelled(result);        } else {            //将结果发传递给onPostExecute方法            onPostExecute(result);        }        //最后将AsyncTask的状态设置为完成状态        mStatus = Status.FINISHED;    }

finish方法内部会首先判断AsyncTask是否被取消了,如果被取消了执行onCancelled(result),否则执行onPostExecute(result)方法。需要注意的是InternalHandler是指向主线程的,所以其handleMessage方法是在主线程中执行的,从而此处的finish方法也是在主线程中执行的,进而onPostExecute也是在主线程中执行的。

上面我们知道了任务从开始执行到onPostExecute的过程。我们知道,doInBackground方法是在工作线程中执行比较耗时的操作,这个操作时间可能比较长,而我们的任务有可能分成多个部分,每当我完成其中的一部分任务时,我们可以在doInBackground中多次调用AsyncTask的publishProgress方法,将阶段性数据发布出去。

publishProgress方法代码如下所示:

@WorkerThread    protected final void publishProgress(Progress... values) {        if (!isCancelled()) {            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,                    new AsyncTaskResult(this, values)).sendToTarget();        }    }

我们需要将阶段性处理的结果传入publishProgress,其中values是不定长数组,如果任务没有被取消,就会通过InternalHandler创建一个Message对象,该message的Message Code标记为MESSAGE_POST_PROGRESS,并且会根据传入的values创建AsyncTaskResult,将其作为message的obj属性。然后再将该message发送给InternalHandler,然后InternalHandler会执行handleMessage方法,接收并处理该message,如下所示:

public void handleMessage(Message msg) {            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;            switch (msg.what) {                ...                case MESSAGE_POST_PROGRESS:                    //发布阶段性处理结果                    result.mTask.onProgressUpdate(result.mData);                    break;            }        }

在handleMessage方法中,当message.what为MESSAGE_POST_PROGRESS时,会执行AsyncTask的onProgressUpdate方法,该方法是在主线程中执行的。

AsyncTask无论任务完成还是取消任务,FutureTask都会执行done方法,如下所示:

mFuture = new FutureTask(mWorker) {            @Override            protected void done() {                //任务执行完毕或取消任务都会执行done方法                try {                    //任务正常执行完成                    postResultIfNotInvoked(get());                } catch (InterruptedException e) {                    //任务出现中断异常                    android.util.Log.w(LOG_TAG, e);                } catch (ExecutionException e) {                    //任务执行出现异常                    throw new RuntimeException("An error occurred while executing doInBackground()",                            e.getCause());                } catch (CancellationException e) {                    //任务取消                    postResultIfNotInvoked(null);                }            }        };

无论任务正常执行完成还是任务取消,都会执行postResultIfNotInvoked方法。postResultIfNotInvoked代码如下所示:

private void postResultIfNotInvoked(Result result) {        final boolean wasTaskInvoked = mTaskInvoked.get();        if (!wasTaskInvoked) {            //只有mWorker的call没有被调用才会执行postResult方法            postResult(result);        }    }

如果AsyncTask正常执行完成的时候,call方法都执行完了,mTaskInvoked设置为true,并且在call方法中最后执行了postResult方法,然后进入mFuture的done方法,然后进入postResultIfNotInvoked方法,由于mTaskInvoked已经执行,所以不会执行再执行postResult方法。

如果在调用了AsyncTask的execute方法后立马就执行了AsyncTask的cancel方法(实际执行mFuture的cancel方法),那么会执行done方法,且捕获到CancellationException异常,从而执行语句postResultIfNotInvoked(null),由于此时还没有来得及执行mWorker的call方法,所以mTaskInvoked还未false,这样就可以把null传递给postResult方法。

这样,我们基本就将AsyncTask中的细节都讲到了,希望本文对大家理解AsyncTask的工作原理有所帮助!

相关阅读:
我的Android博文整理汇总
Android中AsyncTask使用详解

更多相关文章

  1. android 线程池的使用
  2. Android的线程使用来更新UI----Thread、Handler、Looper、TimerT
  3. 更新android studio gradle 不成功解决方法
  4. 在android中实现动态跑动的图表实现方法
  5. Android service的开启和绑定,以及调用service的方法
  6. Android中JNI的使用方法
  7. 【解决方法】Unexpected namespace prefix “xmlns” found for
  8. Android Studio下“Error:Could not find com.android.tools.bui
  9. Android 结束进程的方法

随机推荐

  1. 【DB笔试面试712】在Oracle中,启动和关闭
  2. 【DB笔试面试696】在Oracle中,什么OSWatch
  3. 【DB笔试面试702】在Oracle中,如何定时清
  4. 程序员:报警快把我折腾疯了
  5. Vim,第三只手
  6. 【DB笔试面试710】在Oracle中,用哪个参数
  7. 内网绘图服务,老板乐的笑出大金牙
  8. 【DB笔试面试687】在Oracle中,常用的10046
  9. 从源码层次理解Spring事务
  10. 【DB笔试面试683】在Oracle中,什么是ORA-0