• AsyncTask源码分析


    关于AsyncTask的用法可以参看前面一篇博客《AsyncTask实现断点续传》,本文只解析AsyncTask的源代码。
     
    AsyncTask.execute方法:
    1     public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    2         return executeOnExecutor(sDefaultExecutor, params);
    3     }
    execute方法里面直接调用了executeOnexecute方法。
     
    AsyncTask.executeOnexecute方法:
     1     public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
     2             Params... params) {
     3         if (mStatus != Status.PENDING) {
     4             switch (mStatus) {
     5                 case RUNNING:
     6                     throw new IllegalStateException("Cannot execute task:"
     7                             + " the task is already running.");
     8                 case FINISHED:
     9                     throw new IllegalStateException("Cannot execute task:"
    10                             + " the task has already been executed "
    11                             + "(a task can be executed only once)");
    12             }
    13         }
    14         mStatus = Status.RUNNING;
    15         onPreExecute();
    16         mWorker.mParams = params;
    17         exec.execute(mFuture);
    18         return this;
    19     }
            3-13行是检测AsyncTask的状态,如果状态不为PENDING,则会抛异常,这也是为什么一个AsyncTask只能被执行一次的原因。14行将状态改为RUNNING,表示该任务正在运行。然后调用AsyncTask的onPreExecute()方法。
            由下面代码可以看出,AsyncTask有三种状态:PENDING(未运行)、RUNNING(正在运行)、FINISHED(已运行完毕)。
     1     public enum Status {
     2         /**
     3          * Indicates that the task has not been executed yet.
     4          */
     5         PENDING,
     6         /**
     7          * Indicates that the task is running.
     8          */
     9         RUNNING,
    10         /**
    11          * Indicates that {@link AsyncTask#onPostExecute} has finished.
    12          */
    13         FINISHED,
    14     }
     
            FutureTask代码:
     1 public class FutureTask<V> implements RunnableFuture<V> {
     2     ......
     3     //构造方法传入一个Callable对象
     4     public FutureTask(Callable<V> callable) {
     5         if (callable == null)
     6             throw new NullPointerException();
     7         this.callable = callable;
     8         this.state = NEW;       // ensure visibility of callable
     9     }
    10     public void run() {
    11         if (state != NEW ||
    12             !UNSAFE.compareAndSwapObject(this, runnerOffset,
    13                                          null, Thread.currentThread()))
    14             return;
    15         try {
    16             Callable<V> c = callable;
    17             if (c != null && state == NEW) {
    18                 V result;
    19                 boolean ran;
    20                 try {
    21                     result = c.call();//这里调用了callable.call()方法
    22                     ran = true;
    23                 } catch (Throwable ex) {
    24                     result = null;
    25                     ran = false;
    26                     setException(ex);
    27                 }
    28                 if (ran)
    29                     set(result);
    30             }
    31         } finally {
    32             // runner must be non-null until state is settled to
    33             // prevent concurrent calls to run()
    34             runner = null;
    35             // state must be re-read after nulling runner to prevent
    36             // leaked interrupts
    37             int s = state;
    38             if (s >= INTERRUPTING)
    39                 handlePossibleCancellationInterrupt(s);
    40         }
    41     }
    42     ......
    43 }
            AsyncTask构造方法:
     1 public abstract class AsyncTask<Params, Progress, Result> {
     2     ......
     3     /**
     4      * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     5      */
     6     public AsyncTask() {
     7         mWorker = new WorkerRunnable<Params, Result>() {
     8             public Result call() throws Exception {
     9                 mTaskInvoked.set(true);
    10                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    11                 //noinspection unchecked
    12                 return postResult(doInBackground(mParams));
    13             }
    14         };
    15         //创建FutureTask对象的时候传入了mWorker作为Callable
    16         mFuture = new FutureTask<Result>(mWorker) {
    17             @Override
    18             protected void done() {
    19                 try {
    20                     postResultIfNotInvoked(get());
    21                 } catch (InterruptedException e) {
    22                     android.util.Log.w(LOG_TAG, e);
    23                 } catch (ExecutionException e) {
    24                     throw new RuntimeException("An error occured while executing doInBackground()",
    25                             e.getCause());
    26                 } catch (CancellationException e) {
    27                     postResultIfNotInvoked(null);
    28                 }
    29             }
    30         };
    31     }
    32     ......
    33 }
            由FutureTask源码我们可以看出,run()方法里面调用了c.call(),而AsyncTask 中创建FutureTask的时候传入了mWorker,所以FutureTask.run()方法里面c.call()调用的是mWorker对象的call()方法,而AsyncTask里mWorker重写了call方法,即上面8-14行,所以c.call()会执行到mWorker.call()方法来。call方法里面11行将线程的优先级设置为后台线程,这样当多个线程并发后很多无关紧要的线程分配的CPU时间将会减少,有利于主线程的处理。
            接下来11行执行了doInBackground(mParams)方法,通常我们会重写该方法来实现业务逻辑操作。然后执行postResult方法,并且将结果返回给FutureTask(因为是FutureTask.run方法调用的此call方法,所以需要返回结果到FutureTask.run方法)。这里我们先看看postResult:
    1     private Result postResult(Result result) {
    2         @SuppressWarnings("unchecked")
    3         Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
    4                 new AsyncTaskResult<Result>(this, result));
    5         message.sendToTarget();
    6         return result;
    7     }

            这里的sHandler是InternalHandler对象。
     1     private static class InternalHandler extends Handler {
     2         @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
     3         @Override
     4         public void handleMessage(Message msg) {
     5             AsyncTaskResult result = (AsyncTaskResult) msg.obj;
     6             switch (msg.what) {
     7                 case MESSAGE_POST_RESULT:
     8                     // There is only one result
     9                     result.mTask.finish(result.mData[0]);
    10                     break;
    11                 case MESSAGE_POST_PROGRESS:
    12                     result.mTask.onProgressUpdate(result.mData);
    13                     break;
    14             }
    15         }
    16     }

            由第9行代码可知最终会执行AsyncTask的finish方法,代码如下:
    1     private void finish(Result result) {
    2         if (isCancelled()) {
    3             onCancelled(result);
    4         } else {
    5             onPostExecute(result);
    6         }
    7         mStatus = Status.FINISHED;
    8     }

            finish的作用是如果task被取消了就执行onCancelled方法,如果没有被取消而是正常执行完毕,则执行onPostExecute方法(这也是为什么task被调用了cancel方法,不会执行onPostExecute的原因)。最后将task的状态标记为FINISHED。
            
            上面说到mWorker.call会将执行结果返回给FutureTask.run()方法并且继续往下执行,我们再次看看FutureTask.run方法(20-30行):
     1 boolean ran;
     2 try {
     3      result = c.call();
     4      ran = true;
     5 } catch (Throwable ex) {
     6      result = null;
     7      ran = false;
     8      setException(ex);
     9 }
    10 if (ran)
    11      set(result);

            由上面代码可以看到,执行完c.call后,会执行set(result)方法。
    1     protected void set(V v) {
    2         if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
    3             outcome = v;
    4             UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
    5             finishCompletion();
    6         }
    7     }

            最终会执行finishCompletion()方法。
     1     private void finishCompletion() {
     2         // assert state > COMPLETING;
     3         for (WaitNode q; (q = waiters) != null;) {
     4             if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
     5                 for (;;) {
     6                     Thread t = q.thread;
     7                     if (t != null) {
     8                         q.thread = null;
     9                         LockSupport.unpark(t);
    10                     }
    11                     WaitNode next = q.next;
    12                     if (next == null)
    13                         break;
    14                     q.next = null; // unlink to help gc
    15                     q = next;
    16                 }
    17                 break;
    18             }
    19         }
    20         done();
    21         callable = null;        // to reduce footprint
    22     }

            看到21行代码,会执行FutureTask的done()方法,而这个方法在AsyncTask构造函数中初始化FutureTask对象的时候被重写了。
     1     mFuture = new FutureTask<Result>(mWorker) {
     2             @Override
     3             protected void done() {
     4                 try {
     5                     postResultIfNotInvoked(get());
     6                 } catch (InterruptedException e) {
     7                     android.util.Log.w(LOG_TAG, e);
     8                 } catch (ExecutionException e) {
     9                     throw new RuntimeException("An error occured while executing doInBackground()",
    10                             e.getCause());
    11                 } catch (CancellationException e) {
    12                     postResultIfNotInvoked(null);
    13                 }
    14             }
    15         };
            这里主要是验证postResult是否被调用了,如果没有被调用着调用postResult函数,因为前面mWorker.call方法里面调用过了,所以这里不错操作。
     
            顺便提一下,在AsyncTask的doInBackground方法中如果需要更新UI的话,则调用AsyncTask的publishProgress方法即可:
    1     protected final void publishProgress(Progress... values) {
    2         if (!isCancelled()) {
    3             sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
    4                     new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    5         }
    6     }

            publishProgress方法最终也会通过sHandler来调用AsyncTask的onProgressUpdate方法,一般我们如果需要获取进度的话都需要重写AsyncTask的onProgressUpdate。
     
            好了,AsyncTask的源码也分析完了。再次总结一下Asynctask使用的注意事项:

       1.异步任务的实例必须在UI线程中创建。

      2.execute(Params... params)方法必须在UI线程中调用。

      3.不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。

      4.不能在doInBackground(Params... params)中更改UI组件的信息。

      5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。

     
  • 相关阅读:
    查询数据库对象依赖关系
    SQL Server数据库管理员必备:DBCC命令
    使用延迟的FileSystemWatcher来避免重复触发事件
    在Lambda表达式中使用递归
    如何观察SQL Server 生成和重用执行计划
    利用Lambda表达式、扩展方法以及泛型来实现一个另类的AOP
    将 SQL Server 2000 系统表映射到 SQL Server 2005 系统视图[MSDN]
    利用Lambda表达式、扩展方法以及泛型来为对象添加方法
    C# 中编译器是如何实现闭包的
    在ASP.NET中使用FileSystemWatcher来监控文件目录
  • 原文地址:https://www.cnblogs.com/liuling/p/2015-10-10-02.html
Copyright © 2020-2023  润新知