AsyncTask源码浅析

来源:互联网 发布:thinkphp手机商城源码 编辑:程序博客网 时间:2024/06/05 06:45

在开发的过程中我们如果想进行一些耗时的操作不能直接在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中经常使用的。



0 0
原创粉丝点击