Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> AsyncTask源碼探究,asynctask源碼

AsyncTask源碼探究,asynctask源碼

編輯:關於android開發

AsyncTask源碼探究,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方法只執行了一次。

  



 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved