Android-AsyncTask源码分析

    AsyncTask异步任务类,允许在UI线程中进行后台操作和发布结果到UI线程中,一般使用多操作中,这个类的基本用法可以参照博主写的另一边博文http://blog.csdn.net/nzsdyun123/article/details/22215589这里有讲述AsyncTask的基本用法,今天我也按照上篇分析Handler机制那样带领大家来分析下AsyncTask的流程。

我们一般是这样来开始启动AsyncTask的:

MyAsyncTask myAsyncTask = new MyAsyncTask();

myAsyncTask.execute(path);

这里MyAysncTaskAysncTask的子类,这里我们使用AsyncTask的时候也是一般继承AysncTask类,重写其方法,我们查看AysncTask的源码发现:

/**

 * <p>AsyncTask enables proper and easy use of the UI thread. This class allows to

 * perform background operations and publish results on the UI thread without

 * having to manipulate threads and/or handlers.</p>

 *

 * <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}

 * and does not constitute a generic threading framework. AsyncTasks should ideally be

 * used for short operations (a few seconds at the most.) If you need to keep threads

 * running for long periods of time, it is highly recommended you use the various APIs

 * provided by the <code>java.util.concurrent</code> pacakge such as {@link Executor},

 * {@link ThreadPoolExecutor} and {@link FutureTask}.</p>

AsyncTask是后台UI线程,通过发布结果到UI线程中,同时这里也给我们介绍了AsyncTask被设计成ThreadHandler的一个助手类,适用于短时的线程操作,长时的线程操作被推荐适用线程池ThreadPoolExecutor来解决,及其他的一些基础用法等,从这里的简介中,提到AsyncTask被设计成ThreadHandler的一个助手类?我们这时就要想AsyncTask是不是对Thread+Handler的一个封装?答案是这样吗?我们带着疑问来分析:

当我们调用myAsyncTask.execute(path);这语句时,这时AsyncTask就开始正式工作了。我们来进入源码分析这句:

public final AsyncTask<Params, Progress, Result> execute(Params... params) {

        return executeOnExecutor(sDefaultExecutor, params);

}

这里函数被设计成接收三个泛型数据类型的类,同时参数被设计成可变参数,可以根据实际需求动态的传入参数的个数。我们接着看跟踪 return executeOnExecutor(sDefaultExecutor, params);

 

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,

            Params... params) {

        if (mStatus != Status.PENDING) {//尚未创建AsyncTask

            switch (mStatus) {

                case RUNNING://AsyncTask正在后台运行,抛出异常

                    throw new IllegalStateException("Cannot execute task:"

                            + " the task is already running.");

                case FINISHED://AsyncTask任务已完成

                    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;

        exec.execute(mFuture);

 

        return this;

}

从上述分析可以知道当前UI线程的AsyncTask对象不能多次调用execute方法,关键的是我们看这几句       

        onPreExecute();

 

        mWorker.mParams = params;

        exec.execute(mFuture);

追踪onPreExecute();可以发现这是一个空实现方法:

   /**

     * Runs on the UI thread before {@link #doInBackground}.

     *

     * @see #onPostExecute

     * @see #doInBackground

     */

    protected void onPreExecute() {

}

子类可以重写它,运行在UI线程,在doInBackground方法之前,从这里我们可以知道,既然onPreExecute函数运行在UI线程中,所以我们可以在这做些资源的初始化的工作。接着来分析 mWorker.mParams = params;这句是将参数赋值给mWorker对象的参数。所以我们追踪mWorker对象发现:

    private final WorkerRunnable<Params, Result> mWorker;

    private final FutureTask<Result> mFuture;

它是AsyncTask的类类型对象,那WorkerRunnable到底是什么呢?追踪源码可知:

   private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {

        Params[] mParams;

    }

它是一个抽象类,实现了Callable回调接口,用于从不同的线程来获取结果ResultOK,我们接着分析:

 

 

exec.execute(mFuture);executeOnExecutor函数声明中可以看出execExecutor的对象,Excutor?哇,这不就是线程池的运用嘛(线程池知识这里不讲解),这里简单讲下ExcutorExcutor是一个接口,此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。简单讲就是方便线程的创建和使用。那么exec.execute(mFuture);就是执行线程,那这个mFuture肯定是一个Runnable或者实现Runnable接口的类,追踪mFuture

private final FutureTask<Result> mFuture;

FutureTask?这又是什么呢?我们查看JDK帮助文档可知:

public class FutureTask<V>

extends Object

implements RunnableFuture<V>

它是继承了Object对象,实现RunnableFuture接口的类,当然RunnableFuture实现了Runnable接口,果不其然,由JDK可知

FutureTask是一个可取消的异步计算。利用开始和取消计算的方法、查询计算是否完成的方法和获取计算结果的方法。简单来讲就是获取提供一些方法来开始和取消线程,同时可以获取线程运行后的结果。那么FutureTaskWorkerRunnable对象又是什么时候开始创建的呢?追踪可以发现它们是在我们创建AsyncTask对象时就给我们创建好了:

 /**

     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.

     */

    public AsyncTask() {

        mWorker = new WorkerRunnable<Params, Result>() {//创建WorkerRunnable,并实现Callable接口方法call

            public Result call() throws Exception {

                mTaskInvoked.set(true);//设置标志值

 

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//设置线程优先级

                //noinspection unchecked

                return postResult(doInBackground(mParams));//根据外部传入的参数调用doInBackground方法,并将结果传给postResult函数

            }

        };

 

        mFuture = new FutureTask<Result>(mWorker) {

//创建FutureTask对象,重写done方法

            @Override

            protected void done() {

                try {

                    postResultIfNotInvoked(get());//等到线程执行完成,通过get方法获取线程运行后的结果,传给postResultIfNotInvoked方法

                } 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);

                }

            }

        };

    }

原来这两个对象在AsyncTask类创建的时候就给预先创建好了,前面说到WorkerRunnable是一个实现了Runnable接口的类,当系统执行到exec.execute(mFuture);这句时,这时就会执行线程里的WorkerRunnable的方法,这里们可以看到,AsyncTask的设计者巧妙的使用回调,将需要在线程中运行的语句又交到了我们开发应用者手上,我们查看doInBackground(mParams)就可以知道:

protected abstract Result doInBackground(Params... params);

这是一个抽象的方法,我们子类可以实现它,当然这些语句会运行在另一个线程中,Ok这时我们查看postResultpostResultIfNotInvoked方法:

    private void postResultIfNotInvoked(Result result) {

        final boolean wasTaskInvoked = mTaskInvoked.get();

        if (!wasTaskInvoked) {

            postResult(result);

        }

    }

postResultIfNotInvoked方法最后也是调用postResult方法:

 

    private Result postResult(Result result) {

        @SuppressWarnings("unchecked")

        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,

                new AsyncTaskResult<Result>(this, result));

        message.sendToTarget();

        return result;

}

从这里可以看出,向sHandler所在的线程发送一个消息,并将线程运行后的结果回传过去,ok,这里我们分析sHandler对象的类:

private static final InternalHandler sHandler = new InternalHandler();

 

    private static class InternalHandler extends Handler {

        @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;

            }

        }

}

从上面可以知道,Handler类接收两个消息:MESSAGE_POST_RESULT线程执行完毕后消息,MESSAGE_POST_PROGRESS进度更新消息

result.mTask.finish(result.mData[0]);

我们从这句语句找到finish方法:

    private void finish(Result result) {

        if (isCancelled()) {

            onCancelled(result);

        } else {

            onPostExecute(result);

        }

        mStatus = Status.FINISHED;

    }

要么是调用     */

    @SuppressWarnings({"UnusedParameters"})

    protected void onCancelled(Result result) {

        onCancelled();

    }    

    

onCancelled来取消AysncTask,不然就是等待线程运行完成后,提交给onPostExecute(result);方法处理:

   @SuppressWarnings({"UnusedDeclaration"})

    protected void onPostExecute(Result result) {

}

所以,我们可以在子类中重写onPostExecute这个方法时,获取其结果,而MESSAGE_POST_PROGRESS消息是将结果交于onProgressUpdate(result.mData);处理:

 

    @SuppressWarnings({"UnusedDeclaration"})

    protected void onProgressUpdate(Progress... values) {

    }

这里一般是我们重写时获取进度来进行进度条更新的,那这个消息MESSAGE_POST_PROGRESS又从哪里向handler发送的呢?我们继续追查:

    protected final void publishProgress(Progress... values) {

        if (!isCancelled()) {

            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,

                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();

        }

    }

在这个方法里发送的,这就我们可以解释的同,为什么我们调用

publishProgress的时候,可以在onProgressUpdate接收结果并更新UIpublishProgress是通过handler向创建AsyncTask所在的线程中发送消息并将结果回传过去的。到目前为止,AsyncTask的源码分析就分析的差不多了,这也验证了我们刚开始的猜想,AsyncTask是对Thread+Handler的封装,当然这里不是直接使用Thread的,而已使用静态线程池来进行的,这个查看AsyncTask的各个属性声明就可以知道,当然这也带来了一些限制,那就是线程数不能创建太多。

 

 

 

 

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。