AsyncTask 源码解析

这是 AsyncTask 源码的简单分析,主要基于《Android 开发艺术探索》一书的内容。

AsyncTask 是 Android 中多线程处理方式之一(其余为 1.HandlerThread、2.IntentService 以及普通的线程 Thread)。

AsyncTask 本质是线程池和 Handler 的包装类,适合实时更新后台任务进度的工作,特别耗时的工作应当交给线程池处理。

AsyncTask 常用方法:

  • onPreExecute()
  • doInBackground()
  • onProgressUpdate()
  • onPostExecute()

AsyncTask 有一下限制:

  1. AsyncTask 对象必须在主线程(UI 线程,下同)创建
  2. AsyncTaskexecute() 必须在主线程调用,且只能被调用一次
  3. 不能直接调用其 4 种常用方法(见上)

使用

  • 继承自 AsyncTask,重写对应方法。(注意如果需要更新进度,要在 doInBackground() 方法中调用 publishProgress() 方法)
  • UI 线程实例化 AsyncTask 对象,并调用其 execute() 方法,传入参数开始执行。。

概述

execute(params) 执行后,将参数 params 传入 mWorker.call() 方法

调用 doInBackground(params) 后台执行任务,同时通过 postResult() 方法发送执行结果,由 InternalHandler.handleMessage() 判断该执行 finish() 还是 onProgressUpdate()

mWorker 传入 mFuture 中作为其 callablerunAndReset() 方法中执行 c.call() 方法。

通过 exec.execute(mFuture) 将其压入 SerialExecutor 线程池中排队,并在 THREAD_POOL_EXECUTOR.execute(mActive) 真正执行。

代码分析

创建对象(代码有节略,下同)

// Creates a new asynchronous task. This constructor must be invoked on the UI thread.
//注意这里的要求,必须在 ui 线程
public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
        ? getMainHandler()//此处创建 InternalHandler 用于在 UI 线程处理消息
        : new Handler(callbackLooper);

    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            try {
                result = doInBackground(mParams);//注意这里会调用 doInBackground() 方法,后台线程
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result);//此处发送 msg 到 mHandler 那里接受处理
            }
            return result;
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {//这里将 mWorker 传了进去
        @Override
        protected void done() {
        }
    };
}

再看 FutureTask

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable; //将 mWorker 当做了他的 callable
    this.state = NEW;       // ensure visibility of callable
}

public void run() {
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                 result = c.call(); //会在这里回调 mWorker 的 call() 方法,即前文所说的 doInBackgroud() 之类的方法
            }
        } finally {
        }
    }

在主线程调用 execute() 方法

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

这里调用方法如下:

@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params) {
    if (mStatus != Status.PENDING) { //此处限制 execute() 只能被执行一次
        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; //将参数传入 mWorker,并一并传入 mFuture 中
    exec.execute(mFuture);//将准备好参数、执行时间的 mFuture 排队放入串行线程池中,等待执行

    return this;
}

这里调用了常用方法之一 onPreExecute();

mWorker 和 mFuture 的关系前文已经描述了,在看一下 exec.execute(mFuture) 执行了什么:

exec 是 execute() 传入的,对应于 sDefaultExecutor,再查下去

    /**
     * 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 volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

再看看 SerialExecutor 这个线程池

//SerialExecutor 主要的作用是将这些线程放到线程池中,并按照串行的顺序依次调用
private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
        //offer() Inserts the specified element at the end of this deque.
        //将 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);//在这里面才是真正的执行线程的内容
        }
    }
}

再仔细看一下 THREAD_POOL_EXECUTOR

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
        CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
        sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;

 //Executes the given task sometime in the future.  The task
 //may execute in a new thread or in an existing pooled thread.
ThreadPoolExector.executr()

以上介绍了线程和线程池部分的内容,接下来看一下在主线程和后台线程之间是如何依靠 handler 机制来传递消息的。

关于构造函数,由于我们开发者只能接触到 AsyncTask() 这个构造函数,所以mHandler=getMainHandler()

public AsyncTask() {
    this((Looper) null);
}
//@hide,普通开发者不可见
public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
            ......
}
    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;//sHandler 是一个类变量,取的是主线程的 looper,所以限制了 AsyncTask 只能在主线程实例化
        }
    }

再看一下 InternalHandler

private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) { //在这里处理后台线程发过来的消息,UI 线程
        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;
        }
    }
}

例如,在 doInBackground() 方法中可以使用 publishProgress() 在后台更新进度,即是使用了 handler 发送消息。

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

最后,AsyncTaskfinish()

private void finish(Result result) {
    //可见,最后会根据情况调用 `onCancelled()` 或者 `onPostExecute()`
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

有想法?欢迎通过邮件讨论。

目录