Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android AsyncTask源碼分析

Android AsyncTask源碼分析

編輯:關於Android編程

Android中只能在主線程中進行UI操作,如果是其它子線程,需要借助異步消息處理機制Handler。除此之外,還有個非常方便的AsyncTask類,這個類內部封裝了Handler和線程池。本文先簡要介紹AsyncTask的用法,然後分析具體實現。

基本用法
AsyncTask是一個抽象類,我們需要創建子類去繼承它,並且重寫一些方法。AsyncTask接受三個泛型參數:

Params: 指定傳給任務執行時的參數的類型
Progress: 指定後台任務執行時將任務進度返回給UI線程的參數類型
Result: 指定任務完成後返回的結果的類型
除了指定泛型參數,還需要根據需要重寫一些方法,常用的如下:

onPreExecute(): 這個方法在UI線程調用,用於在任務執行前做一些初始化操作,如在界面上顯示加載進度控件
doInBackground: 在onPreExecute()結束之後立刻在後台線程調用,用於耗時操作。在這個方法中可調用publishProgress方法返回任務的執行進度
onProgressUpdate: 在doInBackground調用publishProgress後被調用,工作在UI線程
onPostExecute: 後台任務結束後被調用,工作在UI線程
源碼分析
下面分析這個類的實現,主要有線程池以及Handler兩部分。

1、線程池
當執行一個AsyncTask的時候調用的是execute()方法,就從這個開始看:

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)"); 
      
      
  } 
 } 
 
 mStatus = Status.RUNNING; 
 //先執行 onPreExecute
 onPreExecute(); 
 
 mWorker.mParams = params; 
 
 exec.execute(mFuture); 
 return this; 
} 

execute方法會調用executeOnExecutor。在這個方法中先檢查任務是否已經執行或者執行結束,然後把任務標記為running。最開始執行的是onPreExecute,接著把參數賦值給mWorker對象。這個mWorker是一個Callable對象,最終被包裝為FutureTask,代碼如下:

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { 
 Params[] mParams; 
} 

mWorker = new WorkerRunnable<Params, Result>() { 
  public Result call() throws Exception { 
   mTaskInvoked.set(true); 

   Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 
   //noinspection unchecked 
   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); 
  } 
 } 
}; 

從上面的代碼可以看出,在mWorker對象中的call()方法會調用doInbackground,返回值交給postResult方法,這個方法通過Handler發送消息,這一點稍後再詳細分析。

在mWorker對象被封裝成FutureTask之後交由線程池執行,從execute方法可以看出,使用的是sDefaultExecutor,它的值默認為SERIAL_EXECUTOR,也就是串行執行器,實現如下:

 private static class SerialExecutor implements Executor { 
 //線性雙向隊列,用來存儲所有的AsyncTask任務 
 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); 
 //當前正在執行的AsyncTask任務 
 Runnable mActive; 

 public synchronized void execute(final Runnable r) { 
  //將新的AsyncTask任務加入到雙向隊列中 
  mTasks.offer(new Runnable() { 
   public void run() { 
    try { 
     //執行AsyncTask任務 
     r.run(); 
    } finally { 
     //當前任務執行結束後執行下一個任務
     scheduleNext(); 
    } 
   } 
  }); 
  if (mActive == null) { 
   scheduleNext(); 
  } 
 } 

 protected synchronized void scheduleNext() { 
  //從任務隊列中取出隊列頭部的任務,如果有就交給並發線程池去執行 
  if ((mActive = mTasks.poll()) != null) { 
   THREAD_POOL_EXECUTOR.execute(mActive); 
  } 
 } 
}

public static final Executor THREAD_POOL_EXECUTOR 
  = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, 
    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); 

在上面的代碼中,如果有任務執行,那麼SerialExecutor的execute方法會被調用,它的邏輯是把Runnable對象加入ArrayDeque隊列中,然後判斷mActivie是否為空。第一次執行時mActive當然為空,所以執行scheduleNext,其實就是取出任務隊列中的第一個任務交給線程池(THREAD_POOL_EXECUTOR)執行。加入mTask隊列的Runnable對象的run方法裡最終一定會調用scheduleNext,那麼又會從任務隊列中取出隊頭任務執行。這樣便實現了單線程順序執行任務,所以在AsyncTask中默認啟用的是單線程執行,只有上一個任務執行後才會執行下一個任務。如果想要啟用多線程執行任務,可以直接調用 executeOnExecutor(Executor exec,  Params... params),這裡的Executor參數可以使用AsyncTask自帶的THREAD_POOL_EXECUTOR,也可以自己定義。

2、Handler
AsyncTask內部用Handler傳遞消息,它的實現如下:

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

如果消息類型是任務執行後的返回值(MESSAGE_POST_RESULT)將調用finish()方法:

private void finish(Result result) { 
 if (isCancelled()) { 
  onCancelled(result); 
 } else { 
  onPostExecute(result); 
 } 
 mStatus = Status.FINISHED; 
} 

從上面可以知道,如果任務取消了,將調用onCancelled,否則調用onPostExecute,所以一個AsyncTask任務如果取消了,那麼onPostExecute將不會得到執行。

如果消息類型是執行進度(MESSAGE_POST_PROGRESS)將調用onProgressUpdate,這個方法默認是空方法,我們可以根據自己的需要重寫。

總結
AsyncTask的主要邏輯就如上面所分析的,總結幾個需要注意的地方:

      1)、 AsyncTask的類必須在UI線程加載(從4.1開始系統會幫我們自動完成)
      2)、  AsyncTask對象必須在UI線程創建
      3)、  execute方法必須在UI線程調用
      4)、  不要手動調用onPreExecute()、doInBackground、onProgressUpdate方法
      5)、  一個任務只能被調用一次(第二次調用會拋出異常)

其它還有一些細節可以自行研究源碼,另外推薦幾篇不錯的文章:

Android AsyncTask完全解析,帶你從源碼的角度徹底理解

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