AsyncTask工作原理解析

因为这是我第一次写源码的解析,说得不清楚或者不正确的还望指正。
线程在android中扮演了很重要的角色,但归根到底就是主线程(UI线程)和子线程。在子线程中不能修改UI控件,而在主线程中又不能做耗时的操作。所以说如果既要做耗时的操作,又要修改UI控件的话,就会显得很麻烦,幸好android封装了这一功能,就是AsyncTask,里面是封装了线程池和Handler。
AsyncTask的调用是new MyAsyncTask().execute(),所以我们就从execute()开始看。

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

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
       ......

        mStatus = Status.RUNNING;

        onPreExecute();

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

        return this;
    }

首先调用的是executeOnExecutor(Params… params),再调用executeOnExecutor(Executor exec,
Params… params)方法。
在这里面,我们看到了onPreExecute(),就是做一些准备工作的。再往下看,出现了mWorker.mParams = params;
exec.execute(mFuture);
这两句,那么mWorker是什么,mFuture又是什么,还有那个exec。
好,我们现在先来看mWorker.。

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

private final WorkerRunnable<Params, Result> mWorker;

mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(result);
            }
        }; 

原来,mWorker是Callable子类,而Callble其实相当于就是一个Runnable线程,run()方法换成了call()方法而已。跟Runnable不同的是Callble是有返回值的,而Runnable是没有的。
接着看下去,Result result = doInBackground(mParams),原来最耗时的doInBackground()在这里执行,而且还有一个返回值,Result。最后的postResult(result),肯定就是将结果返回主线程。这部分稍后再讲。

我们再看看mFuture是什么?

private final FutureTask<Result> mFuture;

public AsyncTask() {

         ............

        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 occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

这里又出现了FutureTask这个类,这个类究竟是什么呢?我们来看看它的定义:

public class FutureTask<V> implements RunnableFuture<V>{
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
}

原来又是一个线程,而这个线程是实现了RunnableFuture接口。RunnableFuture是可以被多线程下执行,并且能够异步的取得结果。
mFuture在构造函数里面传入了参数mWorker,而在done()方法里面执行了postResultIfNotInvoked(get());
get()是表示获取mWorker的call的返回值,即Result。然后调用postResultIfNotInvoked(),下面来看看这个方法

private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

哈哈,原来又是有postResult(result),又是返回主线程,通知控件修改,这块一会再讲。
来到这里,已经说明了mWorker和mFuture这两个了。接着就是讲exec.execute(mFuture)中的exec了,就是一开始提到的那里,没有忘记吧!

exec原本是executeOnExecutor(ExecuteOnExecutor exec,…)中传进来的参数,那我们再看之前传进来的是executeOnExecutor(sDefaultExecutor, params),原来是sDefaultExecutor,那我们就看看这个sDefaultExecutor是何方神圣!

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
            }
        }
    }

原来sDefaultExecutor就是一个SerialExecutor线程池。而mTasks其实是一个线程任务队列。

ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();

当没有正在活动的AsyncTask任务,就会调用scheduleNext()这个方法。
那我们再看看这个方法是怎样的:

protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

这里又出现一个线程池THREAD_POOL_EXECUTOR,原来真正地执行任务的是THREAD_POOL_EXECUTOR线程池,而SerialExecutor这个线程是用于任务的队列。

好了,我们先来总结一部分先,AsyncTask的排队执行过程。首先系统会将传进来的参数params封装到mWorker这个线程中,接着mWorker这个参数会传进FutureTask对象中去。因为FuntureTask相当于是一个线程,第一个线程池SerialExecutor就会把这个mFuture这个线程插进任务队列,如果当前没有执行的AsyncTask,就会调用scheduleNext(),就是THREAD_POOL_EXECUTOR这个真正执行任务的。而从SerialExecutor的execute()方法可以看出,AsyncTask任务执行完成之后,会继续执行scheduleNext(),所以这可以看出AsyncTask默认情况下是串行的。

来到这里的话,基本就分析完毕了,但是好像漏了之前postResult(result)这个方法。从名字上可以看出,这个方法应该就是将结果返回到主线程中,那我们来验证一下。

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

在这里我们看到了熟悉的Message,本能反应的,应该会想到应该有一个handler。

private static class InternalHandler extends Handler {
        public 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:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

没错,就是通过发送MESSAGE_POST_RESULT这个消息通知InternalHandler,再调用finish()方法。

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

而InternalHandler是在主线程中创建的,所以可以访问UI控件。这也就是要求我们的AsyncTask的类必须要在主线程中创建。

至此,AsyncTask的源码和工作流程就分析完毕了。这里再补充两点:

  • Android 3.0以前,是并发的
  • Android 3.0以后,默认情况下是串行的,相当于是单线程执行。如果想要在3.0及以上并发,就可以采用AsyncTask的executeOnExecutor()方法

猜你喜欢

转载自blog.csdn.net/lihuanxing/article/details/52445098