AsyncTask异步任务机制源码分析和总结笔记

 概述

 AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线中更新UI。从显现上来说,AsyncTask封装了Thread和Handler,通过AsyncTask可以更加方便地执行后台任务以及在主线程中访问UI,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的后台任务,建议使用线程池。

        Asynctask是一个抽象的泛型类,它提供了Params,Progress和Result这三个泛型参数,其中Params表示参数的类型,Progress表示后台任务执行进度的类型,而Result则表示后台任务返回数据的类型,如果AsyncTask确实不需要传递具体的参数,那么这三个泛型参数可以用Void来代替。

核心方法和基本执行流程

(1)onPreExecute(),在主线程中执行,一般在异步任务执行之前被调用,可以用于做些准备工作。比如,弹出进度加载框;

(2)doInBackground(Params… params),在线程池中执行,此方法用于执行异步任务,params参数表示异步任务输入的参数。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdata方法。另外此方法需要返回计算结果给onPostExecute方法。

(3)onProgressUpdata(Progress…values),在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用。

(4)onPostExecute(Result result),在主线程中执行,在一部任务执行之后,此方法会被调用,其中result参数是后台任务的返回值,即doInBackground的返回值。


上面几个方法,onPreExecute先执行,接着是doInBackground,最后才是onPostExecute。除了上述四个方法以外,AsyncTask还提供了onCancelled()方法,他同样是在主线程中执行,当异步任务被取消时,onCancelld()方法会被调用,这时候onPostExecute则不会被调用。


AsyncTask工作原理和源码解析

介绍了AsyncTask的基本情况后,我们知道了它是封装了Handler和线程池,那我们来分析一下它底层到底是如何执行的,我们从execute方法开始分析。 

我们创建了AsyncTask对象后,紧接着就会调用execute()方法去执行异步任务。

MyAsyncTask task = new MyAsyncTask();
task.execute();


而在execute()方法中又会调用executeOnExecutor方法:

 @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
@MainThread
    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();

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

        return this;
    }


上面的代码中,sDefaultExecutor实际上是一个串行的线程池,一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行,在executeOnExecutor方法中,AsyncTask的onPreExecute()方法最先执行,然后下面线程池开始执行。


  在线程池中实现的是AsyncTask的排队执行过程,首先系统会把AsyncTask的Params的参数封装成FutureTask对象,FutureTask是一个并发类,充当了Runnable的作用。在FutureTask的run方法中会调用mWorker的call方法。


在AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中第一个线程池用于任务的排队,而第二个线程池THREAD_POOL_EXECUTOR用于真正的执行任务。InternalHandler用于将执行环境从线程池切换到主线程。



doInBackground(Params…params)方法会在这里面执行将其返回值传递给postResult方法。


在postResult方法会通过sHandler发送一个MESSAGE_POST_RESULT的消息,这个sHandler的定义如下:



可以发现,sHandler是一个静态的Handler对象,为了能够将执行环境切换到主线程,这就要求sHandler这个对象必须在主线程中创建。由于静态成员会在加载类的时候进行初始化,因此这就变相要求AsyncTask必须在主线程中加载,否则同一个进程中的AsyncTask都将无法正常工作。sHandler收到MESSAGE_POST_RESULT消息后会调用AsyncTask的finish方法

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


AsyncTask的finish方法的中,如果AsyncTask被取消执行了,那么久调用onCancelled方法,否则就会调用onPostExecute方法,可以看到doInBackground的返回结果就会传递给onPostExecute方法,这里AsyncTask的整个工作就执行完了。

另外,AsyncTask在Android 3.0之前是并行执行,在Android 3.0开始,在默认情况下是串行执行的。如何想要AsyncTask在Android 3.0并行执行,可以采用AsyncTask的executeOnExecutor方法。需要注意的是这个方法是Android 3.0新添加的方法,并不能在低版本上使用。


AsyncTask在使用的过程中的条件限制和注意点

(1)   AsyncTask的类必须是在主线程中加载,这就意味着第一次访问AsyncTask必须发生在主线程,当然这个过程在Android 4.1及以上版本已经被系统自动完成了。在Android 5.0的源码中,可以查看ActivityThread的mian方法,它会调用AsyncTask的init方法,这就满足了AsyncTask的类必须在主线程中进行加载这个条件了。

(2)   AsyncTask的对象必须在主程中创建。

(3)   execute方法必须在UI线程调用。

(4)   不要在程序中直接调用onpreExecute(),doInBackground, onProgressUpdata和onPostExecute方法。

(5)   一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常。

(6)   在Android 1.6之前,AsyncTask是串行执行任务的,Android 1.6的时候AsyncTask开始采用线程池来处理并行任务,但是从Android 3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask有采用一个线程来串行执行任务。尽管如此,在Android 3.0之后的版本,我们仍可以通过AsyncTask的executeOnExecutor方法来并行执行认为。





猜你喜欢

转载自blog.csdn.net/ding_gc/article/details/52882265