你的位置:首页 > 操作系统

[操作系统]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 to33       // prevent concurrent calls to run()34       runner = null;35       // state must be re-read after nulling runner to prevent36       // leaked interrupts37       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 unchecked12         return postResult(doInBackground(mParams));13       }14     };15     //创建FutureTask对象的时候传入了mWorker作为Callable16     mFuture = new FutureTask<Result>(mWorker) {17       @Override18       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 state5       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 gc15           q = next;16         }17         break;18       }19     }20     done();21     callable = null;    // to reduce footprint22   }





        看到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.一个任务实例只能执行一次,如果执行第二次将会抛出异常。