码迷,mamicode.com
首页 > 其他好文 > 详细

AsyncTask源代码浅析(一)

时间:2014-10-23 22:43:22      阅读:267      评论:0      收藏:0      [点我收藏+]

标签:android   style   blog   io   os   ar   使用   java   sp   

在android开发过程中AsyncTask会经常跟它打交道,网上也有不少对于它的说明,所以在这里就不说它的使用方法了,直接写
自己对它的一些学习心得以及浅显的理解,错误之处忘批评指正。

1.AsyncTask的三个状态:
AsyncTask是一个抽象类,提供了一个抽象方法doInBackground来供子类实现,以便让使用者自己来实现一些比较耗时的工作。
在AsyncTask的生命周期中任务分为三个状态,有变量mStatus来控制,mStatus为枚举类型,枚举类的名称为Status:
PENDING状态:标志这个任务还没有被执行过,该状态在定义状态变量mStatus的时候就被初始化了。
private volatile Status mStatus = Status.PENDING;
RUNNING状态:标志这个任务已经被执行 ,当你调用execute执行任务的execute的时候会设置mStatus = RUNNING;
FINISHED状态:在执行finish(Result result)方法的时候会设置mStatus = FINISHED;至于finish()方法的执行时机是任务执行完以后有handler发送一条相关信息,然后在
handleMessage里面调用。事实上onPostExecute就是在finish里面被调用的。

这三个状态的作用是防止一个AsyncTask的对象多次调用execute方法(事实上AsyncTask的一个对象只能被执行一次就是通过Status枚举来控制的),比如当前的AsynTask对象的mStatus为RUNNING或者FINISHED的时候你再调用execute方法的时候就会抛出异常了
看看execute的代码就可以知道:
 
  /**
     * 执行任务的入口方法
     * @param params
     * @return
     */
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    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)");
            }
        }
        //标志任务正在运行,如果再次调用该对象的execute方法的话,会走517行代码逻辑
        mStatus = Status.RUNNING;
        //任务开启前执行的方法,此时仍然在UI线程中
        onPreExecute();
        //保存参数
        mWorker.mParams = params;
        //执行任务
        exec.execute(mFuture);

        return this;
    }


看executeOnExecutor方法,可以知道当第一次调用execute方法的时候executeOnExecutor里面的if条件是不成立的,当再次调用execute方法的时候if条件成立,然后就会抛出异常。通过观察这个方法,可以发现很多的信息,比如onPreExecute()方法就是先于其他方法执行,此时执行onPreExecute方法的时候仍在在UI线程中,所以我们可以重写这个方法以实现在执行任务之前进行其他处理的问题:比如显示加载滚动条等。接着会执行exec.exeute(mFuture)方法来在UI线程上开启一个新的线程来执行耗时的任务:也就是执行你重写的doInBackground()方法。我们知道AsyncTask的doInBackgound方法是有返回值的,这个返回值可以传给onPreExecute(Reusult result)方法,然后做具体的处理,也就是我们会从线程中获取一个返回值。


在仔细分析之前先说几个多线程编程的几个相关的类:
Callable:为接口提供了一个call()方法,实现该接口的类可作为被其它线程执行的任务,这点和Runnable一样。与Runnable的run方法不同的是call()方法可以返回是有返回值的(Callable就相当于一个有返回结果的Runnable),所以Callable可以用来执行那些存在延迟计算的任务。鉴于AsyncTask的目的有时候就是用来执行耗时的任务并且用该任务的运行结果来修改UI,所以可以想象的出AsyncTask里面肯定会有Callable的身影;在开发中使用AsyncTask的时候肯定会重写doInbackgound()方法,把耗时的任务放在里面执行,事实上doInBackground方法就是在一个Callable的call方法里面执行的,并且利用到了Callable可以有返回值得这一特性来把doInBackground的返回值返回并有FutureTask来获取到这一个返回结果,然后经过一系列的辗转最终交给onPostExecute方法来处理(这么说也许有点理论不足,毕竟我是先看了源码才写这个笔记的,事先已经知道了源码中Callable的存在;姑且在这里做个说明,毕竟后面还得仔细分析)

一句废话:Callable可以返回计算结果,这个结果并不只是一个数字,其实结果可以是一个基本类型,也可以是返回一个对象当然也可以返回一个集合。

FutureTask:表示一种抽象的可生成结果的计算,它表示的计算结果是通过Callable来实现的,FutureTask将计算结果从执行计算的线程传递到获取这个运算结果的线程(摘自Java并发编程实践).可以通过FutureTask的get()方法来获取任务的计算结果.其中get()并不是立即就可以得到运算结果:如果任务已经完成运算的话,就会立即返回结果,否则get方法将会被阻塞直到任务完成后返回运算结果(当然也可能产生异常).通过查看它的源码可以发现FutureTask提供了一个空的方法done(),该方法在任务线程执行完的时候调用,所以程序员自己可以写一个FutureTask的子类来重写这个方法来处理任务线程执行完后的逻辑。当然这个在AsyncTask的源码中得到了体现。注意FutureTask在进入完成状态之后,该FutureTask会永远停止在这个状态上;通过观察AsyncTask的源码可以知道,代码中的FutureTask只有在构造器中初始化了一次,源码中并没有给该类提供了再次初始化FutureTask的方法所以这也是为什么AsyncTask只会被执行一次的元婴。同时,FutureTask还有一个cancel(boolean)的方法可以用来取消正在运行的任务。实际上AsyncTask的取消任务的方法就是简单的调用FutureTask的cancel方法来完成的。总结:一般FutureTask用来执行比较耗时的计算,在任务执行的过程中也可以调用cancel方法来强制取消任务的执行。同时它可以让程序员知道任务线程执行完的时机并可以获取任务线程返回的结果,然后用这个结果在主线程中做一些处理。比如在AsyncTask的onPostExecte方法中就可以用返回的结果来修改UI线程的界面。

通过上面的说明以及AsyncTask的源码可以总结出一下几点:
1.不管你重写不重写onPreExecute()方法,这个方法必定先执行。
2.doInBackground方法交给一个Callable的call方法执行,并且通过FutureTask的get方法获取
3.当doInBackground方法执行完的时候,FutureTask的done方法中会通过Handler发送一条消息,该消息绑定了doInBackground运行的结果,然后在
handleMessage方法中进行处理,也就是交给了onPostExecute方法进行处理

带着上面的几点,先看看Callable和FutureTask的初始化的位置以及具体都它们是怎么处理doInBackground()的,源码如下:
 
public AsyncTask() {
        初始化mWorker
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
               //设置控制变量为true
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                //doInBackground方法再此执行
                return postResult(doInBackground(mParams));
            }
        };

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


以上代码简单说明:
WorkerRunnable是AsyncTask的抽象的嵌套内部类,它实现了Callable接口。在call()方法中会执行postResult()方法,该方法的参数正是doInBackground()
运行过后的返回值(注意:这儿正是doInBackground的执行的地方).看看那postResult()方法的都干了些什么
   private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
 }


 可以看到它发送了一条message,那么就看看该message在Handler的handleMessage方法里面是怎么处理的。
 
 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;
            }
        }
    }



 result.mTask.finish(result.mData[0]);调用了AsyncTask的finish方法,就如前面所说finish方法体里面正好调用了onPostExecute方法,finish方法如下
 
private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            //onPostExecute在此处调用
            onPostExecute(result);
        }
        //设置任务的状态为FINISHED
        mStatus = Status.FINISHED;
    }
    


至此一个AsyncTask的异步任务就会执行完毕,还有个FutureTask的done方法没说明,done()方法调用了postResultIfNotInvoked(get()),其方法如下
private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }


可以看出当if条件成立的时候仍然会执行postResult方法。

查看FutureTask的源码可知在调用cancel()方法取消任务的时候会执行这个done()方法,在发生异常的时候同样会执行这一方法

未完待续,如有错误之处,欢迎批评指正

AsyncTask源代码浅析(一)

标签:android   style   blog   io   os   ar   使用   java   sp   

原文地址:http://blog.csdn.net/chunqiuwei/article/details/40405277

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!