Android中只能在主線程中進行UI操做,若是是其它子線程,須要藉助異步消息處理機制Handler。除此以外,還有個很是方便的AsyncTask
類,這個類內部封裝了Handler
和線程池。本文先簡要介紹AsyncTask
的用法,而後分析具體實現。android
AsyncTask
是一個抽象類,咱們須要建立子類去繼承它,而且重寫一些方法。AsyncTask
接受三個泛型參數:多線程
Params
: 指定傳給任務執行時的參數的類型Progress
: 指定後臺任務執行時將任務進度返回給UI線程的參數類型Result
: 指定任務完成後返回的結果的類型除了指定泛型參數,還須要根據須要重寫一些方法,經常使用的以下:併發
onPreExecute()
: 這個方法在UI線程調用,用於在任務執行前作一些初始化操做,如在界面上顯示加載進度控件doInBackground
: 在onPreExecute()
結束以後馬上在後臺線程調用,用於耗時操做。在這個方法中可調用publishProgress
方法返回任務的執行進度onProgressUpdate
: 在doInBackground
調用publishProgress
後被調用,工做在UI線程onPostExecute
: 後臺任務結束後被調用,工做在UI線程下面分析這個類的實現,主要有線程池以及Handler
兩部分。異步
當執行一個AsyncTask
的時候調用的是execute()
方法,就從這個開始看:ide
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
發送消息,這一點稍後再詳細分析。post
在mWorker
對象被封裝成FutureTask
以後交由線程池執行,從execute
方法能夠看出,使用的是sDefaultExecutor
,它的值默認爲SERIAL_EXECUTOR
,也就是串行執行器,實現以下:this
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
,也能夠本身定義。.net
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
的主要邏輯就如上面所分析的,總結幾個須要注意的地方:
AsyncTask
的類必須在UI線程加載(從4.1開始系統會幫咱們自動完成)AsyncTask
對象必須在UI線程建立execute
方法必須在UI線程調用onPreExecute()
、doInBackground
、onProgressUpdate
方法AsyncTask
默認是串行執行,能夠改成併發執行,但要注意資源同步的問題。AsyncTask
任務填滿線程池的隊列會拋出異常。其它還有一些細節能夠自行研究源碼,另外推薦幾篇不錯的文章: