AsyncTask源码剖析

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.)

AsyncTask 是用来帮助我们更好的使用 ThreadHandler,最好是用于处理短时间异步任务。

使用 AsyncTask 解决异步问题

 1// 实现AsyncTask的子类
2class MyAsyncTask(val name: String) : AsyncTask<Params, Progress, Result>() {
3
4    // 执行任务之前的准备工作,比如将进度条设置为Visible,工作在主线程
5    override fun onPreExecute() {
6        Log.d("async""onPreExecute")
7    }
8
9    // 在onPreExecute()执行完之后立即在后台线程中调用
10    override fun doInBackground(vararg params: String?): Any? {
11        Log.d("async""$name execute")
12        Thread.sleep(1000)
13        publishProgress(1)
14        return null
15    }
16
17    // 调用了publishProgress()之后,会在主线程中被调用,用于更新整体进度
18    override fun onProgressUpdate(vararg values: Int?) {
19        Log.d("async""progress is: $values")
20    }
21
22    // 后台线程执行结束后,会把结果回调到这个方法中,并在主线程中被调用
23    override fun onPostExecute(result: Any?) {
24        Log.d("async""onPostExecute")
25    }
26}
27
28// 调用
29MyAsyncTask("one").execute("")
30MyAsyncTask("two").execute("")
31MyAsyncTask("three").execute("")
32MyAsyncTask("four").execute("")
33
34// 结果
35// 19:29:01.472 1786-1805/com.taonce D/async: one execute
36// 19:29:02.514 1786-1832/com.taonce D/async: two execute
37// 19:29:03.868 1786-1833/com.taonce D/async: three execute
38// 19:29:04.871 1786-1833/com.taonce D/async: four execute

AsyncTask 必须被子类实例化才能使用,其中必须要实现的方法是:doInBackground(vararg params: String?): Any? , 其余三个方法是可选取实现的,具体的解释在上面的代码中都解释过了。还剩下三个泛型参数,下面一一来解释下:

  • Params:执行任务所需要的信息;

  • Progress:执行任务的时候,对外发布的进度;

  • Result:任务执行完成后的结果。

到这为止,你是否发现了一个现象,在结果打印的信息中,每个日志都是相隔1s,仔细看看是不是,暂且留下一个坑放着,后面会分析给大家听。下面开始进入源码分析:

构造函数

先简单的分析下构造函数中的代码:

 1public AsyncTask(@Nullable Looper callbackLooper) {
2    // 初始化mHandler,如果callbackLooper为空或者为sMainLooper,那就使用getMainHandler()的Handler
3    // 否则使用传进来的callbackLooper
4    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
5        ? getMainHandler()
6        : new Handler(callbackLooper);
7    // 初始化一个WorkerRunnable对象,它是Callable的实现类,它的call()方法可以拥有返回值
8    mWorker = new WorkerRunnable<Params, Result>() {
9        public Result call() throws Exception {
10            ...
11        }
12    };
13    // 初始化FutureTask对象,它传入了mWorker对象
14    mFuture = new FutureTask<Result>(mWorker) {
15        @Override
16        protected void done() {
17            ...
18        }
19    };
20}

mWorkermFuture 暂时不分析,等到调用的时候我们再结合源码看,目前我们只需要知道初始化了这些对象就够了。

execute()

接着我们来看看执行一个任务的入口 execute()

 1@MainThread
2public final AsyncTask<Params, Progress, Result> execute(Params... params) {
3    // 调用executeOnExecutor(executor,params),传入的是sDefaultExecutor
4    return executeOnExecutor(sDefaultExecutor, params);
5}
6
7@MainThread
8public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
9        Params... params)
 
{
10    if (mStatus != Status.PENDING) {
11        switch (mStatus) {
12            // 这里解释了为什么不能重复调用execute()方法
13            case RUNNING:
14                throw new IllegalStateException("Cannot execute task:"
15                        + " the task is already running.");
16            case FINISHED:
17                throw new IllegalStateException("Cannot execute task:"
18                        + " the task has already been executed "
19                        + "(a task can be executed only once)");
20        }
21    }
22    // 将状态标记为Running
23    mStatus = Status.RUNNING;
24    // 调用onPreExecute(),它是最先调用的
25    onPreExecute();
26    // 将params传给mWorker
27    mWorker.mParams = params;
28    // 执行sDefaultExecutor.execute(runnable)方法
29    exec.execute(mFuture);
30    // 返回自身
31    return this;
32}

我们调用 AsyncTask.execute(parasm) 方法其实就是调用了 sDefaultExecutor.execute(mFuture) 方法,我们顺藤摸瓜下去。

 1public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
2private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
3
4private static class SerialExecutor implements Executor {
5    // 双端队列
6    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
7    Runnable mActive;
8
9    public synchronized void execute(final Runnable r) {
10        // 添加到队列中,并且执行runnable.run()
11        mTasks.offer(new Runnable() {
12            public void run() {
13                try {
14                    r.run();
15                } finally {
16                    // 执行完r.run()之后依旧会调用一次scheduleNext()方法
17                    // 也就是循环的取队列中的Runnable,直到Runnable为空
18                    // 从这里就可以看出,任务都是按照串行的形式来执行的,必须等待一个任务执行完毕才去取队列中的下一个,也就解释了开头的每个日志打印相隔1s的原因。
19                    scheduleNext();
20                }
21            }
22        });
23        // mActive第一次必然为空
24        if (mActive == null) {
25            scheduleNext();
26        }
27    }
28
29    protected synchronized void scheduleNext() {
30        // 从队列中取出Runnable,并且让线程池去执行
31        // THREAD_POOL_EXECUTOR是一个线程池,配置在源码的最上方
32        if ((mActive = mTasks.poll()) != null) {
33            THREAD_POOL_EXECUTOR.execute(mActive);
34        }
35    }
36}

SerialExecutor 就是一个实现了 Executor 的静态内部类,它的 execute(runnable) 接收 Runnable 对象,然后在 executeOnExecutor(Executor exec, Params... params) 方法中传入的是 mFuture 对象,所以在执行到 scheduleNext() 的时候,就会调用 mFuturerun() 方法。

FutureTask.run()

 1public void run() {
2    ...
3    try {
4        // 拿到Callable对象
5        Callable<V> c = callable;
6        if (c != null && state == NEW) {
7            V result;
8            boolean ran;
9            try {
10                // 执行Callable.call()方法
11                result = c.call();
12                ran = true;
13            } catch (Throwable ex) {
14                result = null;
15                ran = false;
16                setException(ex);
17            }
18            if (ran)
19                // 将Callable.call()方法set()起来,可通过get()获取
20                set(result);
21        }
22    }...
23}

FutureTask.run() 方法就是调用它的 Callable 变量的 call() 方法,在 AsyncTask 中,传入的 Callable 就是 mWorker 对象,这时候我们就可以把构造函数中的 mWorker 初始化的代码搬出来读一读了。

 1mWorker = new WorkerRunnable<Params, Result>() {
2    public Result call() throws Exception {
3        mTaskInvoked.set(true);
4        Result result = null;
5        try {
6            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7            // 获取doInBackground(params)的返回值
8            result = doInBackground(mParams);
9            Binder.flushPendingCommands();
10        } catch (Throwable tr) {
11            // 出现异常将mCancelled设置为true
12            mCancelled.set(true);
13            throw tr;
14        } finally {
15            // 回调结果
16            postResult(result);
17        }
18        return result;
19    }
20};
21
22private static abstract class WorkerRunnable<ParamsResultimplements Callable<Result{
23    Params[] mParams;
24}

mWorker 其实很简单,就是拿到 doInBackground(params) 的返回值,无论是否出现异常,都将结果回调到主线程,回调的操作看下面的 postResult(result)

1private Result postResult(Result result) {
2    // getHandler()就是获取mHandler对象,默认绑定的是主线程Looper
3    // 而mHandler在构造函数中已经解释过,拿到的就是sHandler
4    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
5            new AsyncTaskResult<Result>(this, result));
6    message.sendToTarget();
7    return result;
8}

通过 getHandler().obtainMessage()获取一个 Message 对象,将消息的 what 设置为 MESSAGE_POST_RESULT 标记为结果不是进度,obj 设置为 AsyncTaskResult 对象,它是一个内部类,包含了 AsyncTaskData[] 两个参数。通过 sHandler 将消息发送出去,然后我们看看它是怎么将 onPostExecute(result) 联系起来的。

sHandlerInternalHandler 的实例,我们从 InternalHandler 的源码中就能得到想要的答案:

 1    private static class InternalHandler extends Handler {
2        public InternalHandler(Looper looper) {
3            super(looper);
4        }
5
6        @SuppressWarnings({"unchecked""RawUseOfParameterizedType"})
7        @Override
8        public void handleMessage(Message msg) {
9            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
10            // 根据消息的类型,调用不同的方法
11            switch (msg.what) {
12                case MESSAGE_POST_RESULT:
13                    // There is only one result
14                    result.mTask.finish(result.mData[0]);
15                    break;
16                case MESSAGE_POST_PROGRESS:
17                    result.mTask.onProgressUpdate(result.mData);
18                    break;
19            }
20        }
21    }

InternalHandler 判断了消息的类型,一种是结果,一种是进度,如果是结果的话,那么就调用 AsyncTaskfinish() 方法;如果是进度的话,那么就调用 onProgressUpdate() 方法,这个方法在前面就已经介绍过了,就是更新整体进度的方法,我们只要看下 finish() 方法就ok了:

 1    private void finish(Result result) {
2        // 任务是否被取消
3        if (isCancelled()) {
4            // 任务被取消的话,那么就调用onCancel(),这个方法也是可以重写的
5            onCancelled(result);
6        } else {
7            // 没有被取消就去调用onPostExecute()
8            onPostExecute(result);
9        }
10        // 将状态置为FINISHED
11        mStatus = Status.FINISHED;
12    }

源码分析到此的话,大致的流程已经完成了,通过 execute() 方法将需要执行的任务添加到 SerialExecutor 的双端队列中,然后让 THREAD_POOL_EXECUTOR 线程池去依次执行队列中的 FutureTask.run() ,这里需要注意,执行任务是一个一个执行,执行结束之后再去执行另外一个,这个线程池相当于单线程模式,以串行的形式来执行任务的,而不是并行来执行,整个线程池中真正工作的只有那一个核心线程。通过执行 FutureTask.run() 方法去间接执行 mWorker.call() 方法,在 call() 方法中获取 doInBackground() 方法返回的结果,最后通过 postResult()InternalHandler 来将结果回调到 onPostExecute() 方法中。

源码分析的文章还在不断的更新,如果本文章你发现有不正确或者不足之处,欢迎你在下方留言或者扫描下方的二维码留言也可!

AsyncTask源码剖析


原文始发于微信公众号(Taonce):AsyncTask源码剖析