AsyncTask工作原理解析

来源:互联网 发布:ai mac中文版免费下载 编辑:程序博客网 时间:2024/06/05 07:00

因为这是我第一次写源码的解析,说得不清楚或者不正确的还望指正。
线程在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()方法
0 0
原创粉丝点击