从源码分析AsyncTask

来源:互联网 发布:mac磁盘工具找不到硬盘 编辑:程序博客网 时间:2024/05/22 15:36

AsyncTask是Android提供的一个异步处理的方式。该方式使用较为方便,与Handler相比在代码上显得更简洁。
先来看看使用AsyncTask常用到的几个方法:
1.execute(Params… params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。(在UI线程调用

2.onPreExecute(),在execute(Params… params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。

3.doInBackground(Params… params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress… values)来更新进度信息。

4.onProgressUpdate(Progress… values),在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上。

5.onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。
详细的例子网上也很多了,此处不再列举,以上也是引用的别人的博客所述。
地址:http://blog.csdn.net/liuhe688/article/details/6532519 。
此篇主要是根据源码来分析AsyncTask的原理。

AsyncTask源码分析

老套路,先看看AsyncTask的构造函数。

/**     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.     */    public AsyncTask() {    //WorkerRunnable 为一个继承Callable<Result>接口的虚类        mWorker = new WorkerRunnable<Params, Result>() {            public Result call() throws Exception {                mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                //调用doInBackground 但并不在这开始执行                return postResult(doInBackground(mParams));            }        };        mFuture = new FutureTask<Result>(mWorker) {//初始化mFuture             @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);                }            }        };    }

在构造函数中进行了一些初始化工作,并且最后都调用到了postResult,在postResultIfNotInvoked(get())中,其实最后也调用到了postResult。 这里用到了
Java并发编程:Callable、Future和FutureTask。有兴趣的可以看看。
在上面的代码中,当mWorker中定义的call方法被执行时,doInBackground就会开始执行,我们定义的后台任务也就真正开始了。实际上mFuture对象封装了call方法,当mFuture对象被提交到AsyncTask包含的线程池执行时,call方法就会被调用,我们定义的后台任务也就开始执行了。到此,我们先记住要使doInBackground()方法执行,就需要mFuture被执行,但是执行的地方还没找到。回想我们使用AsyncTask的时候,需要调用execute()方法,让程序跑起来。拿我们就先看看这个方法。

 &emp;我们建立一个继承于一个public abstract class AsyncTask

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

来看看executeOnExecutor方法 和sDefaultExecutor,params参数是一直传到doInBackground方法的。
sDefaultExecutor是什么呢?通过代码可以找到

public static final Executor SERIAL_EXECUTOR = Utils.hasHoneycomb() ? new SerialExecutor() :            Executors.newSingleThreadExecutor(sThreadFactory);private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

sDefaultExecutor 要不是一个 SerialExecutor要不就是一个单线程池。来看看SerialExecutor到底是什么。

private static class SerialExecutor implements Executor {        //mTasks  缓存队列        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);// 执行任务            }        }    }

从上面的代码,可以看出首先由一个缓存队列mTasks ,该队列通过offer添加任务,通过THREAD_POOL_EXECUTOR.execute(mActive)去执行任务。那么接下来就是THREAD_POOL_EXECUTOR了。

 public static final Executor THREAD_POOL_EXECUTOR            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,            TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory,            new ThreadPoolExecutor.DiscardOldestPolicy());

很明显了THREAD_POOL_EXECUTOR就是一个线程池,并且规定了CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,TimeUnit.SECONDS等。从源码中也可以看到

    private static final int CORE_POOL_SIZE = 5;线程池大小5    private static final int MAXIMUM_POOL_SIZE = 128;最大线程数128    private static final int KEEP_ALIVE = 1;存活时间1s

接下来就是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();//该方法被调用,一般用来在执行后台任务前对UI做一些标记。        mWorker.mParams = params;        exec.execute(mFuture);        return this;    }

在代码的倒数第二行exec.execute(mFuture);这个方法。还记得之前mFuture对象么,这就是他被执行的地方了。从而doInBackground方法也就能够执行了,而且还由线程池进行控制。
以上为AsyncTask 调用流程的理解。

1 0