zoukankan      html  css  js  c++  java
  • 通过源码看android系列之AsyncTask

      整天用AsyncTask,但它的内部原理一直没有特意去研究,今天趁着有时间,码下它的原理。

      具体用法就不再说明,相信大家已经用得很熟练了,我们今天就从它怎么运行开始说。先新建好我们的AsyncTask:

    1 class MyAsyncTask extends AsyncTask<String,Integer,Boolean>{
    2 
    3     @Override
    4     protected Boolean doInBackground(String... voids) {
    5         return true;
    6     }
    7 }

      好了,一个最基本的代码已经好了,接下来我们怎么运行它呢?当然,大家都知道的。

    new MyAsyncTask().execute("参数");

      那平时做到这里,我们可能已经不去往不管了,因为已经执行起来了,但是,你有没有想过

    • 为什么调用execute()就可以运行了
    • 为什么doInBackground()方法里面不能操作UI,而onPostExecute就可以

      等等一连串的问题,接下来,我们就一步一步的去看一下,它内部到底做了哪些。

      首先,我们看到它new了一个AsyncTask对象,那我们就去它构建函数看看。

     1     public AsyncTask() {
     2         mWorker = new WorkerRunnable<Params, Result>() {
     3             public Result call() throws Exception {
     4                 mTaskInvoked.set(true);
     5 
     6                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
     7                 //noinspection unchecked
     8                 Result result = doInBackground(mParams);
     9                 Binder.flushPendingCommands();
    10                 return postResult(result);
    11             }
    12         };
    13 
    14         mFuture = new FutureTask<Result>(mWorker) {
    15             @Override
    16             protected void done() {
    17                 try {
    18                     postResultIfNotInvoked(get());
    19                 } catch (InterruptedException e) {
    20                     android.util.Log.w(LOG_TAG, e);
    21                 } catch (ExecutionException e) {
    22                     throw new RuntimeException("An error occurred while executing doInBackground()",
    23                             e.getCause());
    24                 } catch (CancellationException e) {
    25                     postResultIfNotInvoked(null);
    26                 }
    27             }
    28         };
    29     }

      看着很多,其它就是new了两个对象mWorker和mFuture,其实它们分别是Callable和Future的实现,关于它们两个的实现原理,我会在另外一篇文章里讲解。需要注意的是,在实例化mFuture时,把mWorker当作参数传入。现在还没有用到它们,我们接下来往下看execute():

     1     @MainThread
     2     public final AsyncTask<Params, Progress, Result> execute(Params... params) {
     3         return executeOnExecutor(sDefaultExecutor, params);
     4     }
     5 
     6     @MainThread
     7     public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
     8             Params... params) {
     9         if (mStatus != Status.PENDING) {
    10             switch (mStatus) {
    11                 case RUNNING:
    12                     throw new IllegalStateException("Cannot execute task:"
    13                             + " the task is already running.");
    14                 case FINISHED:
    15                     throw new IllegalStateException("Cannot execute task:"
    16                             + " the task has already been executed "
    17                             + "(a task can be executed only once)");
    18             }
    19         }
    20 
    21         mStatus = Status.RUNNING;
    22 
    23         onPreExecute();
    24 
    25         mWorker.mParams = params;
    26         exec.execute(mFuture);
    27 
    28         return this;
    29     }

      我们看到了onPreExecute(),这也解释了它确实比doInBackground运行的早,可以做一些准备工作。接下来,用到了我们前面提到的两个对象,这里是把我们传递过去的参数赋给了mWorker的变量,然后看26行 调用了Executor的execute(),并且把mFuture做为参数传递过去了,那我们看上一个方法,是把sDefaultExecutor当作参数传递过来的,那就看下它的定义:

    1     public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    2     private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

      它的最后实现类是SerialExecutor。我们接着看这个类定义了什么。

     1     private static class SerialExecutor implements Executor {
     2         final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
     3         Runnable mActive;
     4 
     5         public synchronized void execute(final Runnable r) {
     6             mTasks.offer(new Runnable() {
     7                 public void run() {
     8                     try {
     9                         r.run();
    10                     } finally {
    11                         scheduleNext();
    12                     }
    13                 }
    14             });
    15             if (mActive == null) {
    16                 scheduleNext();
    17             }
    18         }
    19 
    20         protected synchronized void scheduleNext() {
    21             if ((mActive = mTasks.poll()) != null) {
    22                 THREAD_POOL_EXECUTOR.execute(mActive);
    23             }
    24         }
    25     }
      这里面,SerialExecutor的方法execute()方法传入的参数Runnable,其实就是我们前面的mFuture(FutureTask实现了Future和Runnable),execute()方法内,会把我们传入的mFuture存入mTasks,这时mActive还等于null,所以会执行scheduleNext(),这样就会从队列中取出第一个,放入线程池中,开始执行,当前也就是我们刚刚放入的mFuture,也就是执行了mFuture的run方法,至于run方法内部怎么运行的,参见我的另一篇文章:Runnable和Future的原理 。总之呢,它就运行了mWorker的call(),为了方便理解,就把mWorker的call()代码从上面copy到这里
    1             public Result call() throws Exception {
    2                 mTaskInvoked.set(true);
    3 
    4                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    5                 //noinspection unchecked
    6                 Result result = doInBackground(mParams);
    7                 Binder.flushPendingCommands();
    8                 return postResult(result);
    9             }

      我们看到,4行修改了线程的优先级,第6行就有我们熟悉的doInBackground(),结果赋给了result,现在是在另外一个线程里面,所以,在doInBackground方法里面是不能操作UI的。最后返回的时候是调用了postResult(),并把结果当参数传入。

    1     private Result postResult(Result result) {
    2         @SuppressWarnings("unchecked")
    3         Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
    4                 new AsyncTaskResult<Result>(this, result));
    5         message.sendToTarget();
    6         return result;
    7     }

      这里面就是我们熟悉的Handler了,查找Handler最后的实现。

     1     private static class InternalHandler extends Handler {
     2         public InternalHandler() {
     3             super(Looper.getMainLooper());
     4         }
     5 
     6         @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
     7         @Override
     8         public void handleMessage(Message msg) {
     9             AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
    10             switch (msg.what) {
    11                 case MESSAGE_POST_RESULT:
    12                     // There is only one result
    13                     result.mTask.finish(result.mData[0]);
    14                     break;
    15                 case MESSAGE_POST_PROGRESS:
    16                     result.mTask.onProgressUpdate(result.mData);
    17                     break;
    18             }
    19         }
    20     }

      根据我们发送消息的CODE 为 MESSAGE_POST_RESULT,我们发现执行的是第13行,仔细看代码会发现,result.mTask其它就是我们的MyAsyncTask对象,调用它的finish方法

    1     private void finish(Result result) {
    2         if (isCancelled()) {
    3             onCancelled(result);
    4         } else {
    5             onPostExecute(result);
    6         }
    7         mStatus = Status.FINISHED;
    8     }

      这就一目了然了,最后会调用我们的onPostExecute方法,并把结果传过去。基本的调用流程就是这样的。

      如果你仔细看了,你可能会发现,mFuture实例化的时候,重写的done()方法并没有介绍到,那它在整个流程中处于什么样的作用呢,我们接下来,单独说一下。

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

      根据名字应该可以猜到,这个方法是在整个异步任务执行完后调用的,在Future中,通过get()就可以获取到我们前面说的mWorker中call方法的返回值(具体原理可看我另一篇文章),那我们再看postResultIfNotInvoked方法,到底对返回的结果做了哪些处理。

    1     private void postResultIfNotInvoked(Result result) {
    2         final boolean wasTaskInvoked = mTaskInvoked.get();
    3         if (!wasTaskInvoked) {
    4             postResult(result);
    5         }
    6     }

      我们看到了postResult(),这个方法,我们在上面刚刚讲过,它是在mWorker的call方法中,返回的时候调用的,你可能会问了,这个方法怎么调用了两次,不慌,我们看上面这个方法的名字,就了了解原因了post result if not invoked ,很明显,这处的调用是防止call()里面没有调用而设置的,开关就是第2行的mTaskInvoked,它是一个AtomicBoolean,具体它干嘛的,自行google,我们发现在call方法里面,有这样一段代码

    mTaskInvoked.set(true);

      所以,在postResultIfNotInvoked方法里面时,如果执行了call方法,这里就会返回true,下面就无法执行,这样就保证了postResult方法只执行了一次。

      



  • 相关阅读:
    【第五章】printf输出顺序
    【转载】面试_现在有4个石头,1000层的楼房,需要测定这个石头破碎的高度。求最少多少次一定可以测出来。
    卷积和积分运算
    【转载】SIFT算法分析(草稿)
    【第五章】指针类型转换
    【第八章】zigzag数组输出
    【转载】SURF算法源码分析(草稿)
    【第六章】const函数改变变量的值——mutable
    Surf算法
    jsp页面中文乱码总结
  • 原文地址:https://www.cnblogs.com/daohen/p/5239858.html
Copyright © 2011-2022 走看看