一、相關基礎
1 用途
用於快速開啟異步任務,處理耗時操作。在線程池中處理異步任務,同時可以將進度和處理結果提交到主線程處理。
2 AsyncTask 泛型參數-Params, Progress, Result
Params 表示傳入doInBackground參數的類型
Progress 表示後臺任務執行進度的類型
Result 表示後臺任務執行完成後返回結果的類型
若不需要傳入具體的參數,傳入Void即可
3 常見方法
onPreExecute 執行任務之前,UI線程,在doInBackground執行之前
doInBackground 執行後臺任務,子線程,can call publishProgress to publish updates on the UI thread
onProgressUpdate 進度更新,UI線程
onPostExecute 任務完成時,UI線程
onCancelled 任務取消時,並且onPostExecute不會執行,UI線程
4 幾個重要名詞
InternalHandler AsyncTask內部Handler,處理任務的提交與更新的消息
SerialExecutor 串行線程池,用於任務調度,任務排隊,一次隻能執行一個任務
THREAD_POOL_EXECUTOR 線程池的實現者,用於真正執行任務
WorkerRunnable 實現瞭Callable接口,用於後臺計算
5 大致流程
1、 onPreExecute , 執行任務之前,運行在UI線程,在doInBackground執行之前
2、 Result = doInBackground() , 執行後臺任務,返回執行結果,在線程池中執行,配合publishProgress來更新任務進度
3、 onProgressUpdate , 在doInBackground方法中調用publishProgress方法,用於進度更新,運行在UI線程(通過內部handler切換到主線程)
4、 onPostExecute , 運行在UI線程,處理運行結果(通過內部handler切換到主線程)
二、 執行流程淺析
1. 首先構造AsyncTask對象,此構造器必須在主線程調用
/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ public AsyncTask() { //實例化WorkerRunnable對象 mWorker = new WorkerRunnable() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } }; // 實例化FutureTask mFuture = new FutureTask(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即WorkerRunnable對象,它是一個抽象類,並實現瞭Callable接口,用於計算一個任務
private static abstract class WorkerRunnable implements Callable { Params[] mParams; }
mFuture即FutureTask對象,下面用到瞭如下構造,
public FutureTask(Callable callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable }
2. 執行一個任務要從它的execute方法開始
execute方法如下,它調用瞭executeOnExecutor方法,可以看到默認使用瞭sDefaultExecutor,即SerialExecutor
public final AsyncTask execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
executeOnExecutor方法,此方法首先檢查運行狀態並賦以新狀態,之後回調onPreExecute方法,並給mWorker賦以參數,最後讓Executor執行任務,並返回AsyncTask對象。
public final AsyncTask 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(); // 在主線程中回調 mWorker.mParams = params; exec.execute(mFuture); // 傳參FutureTask對象 return this; }
exec即Executor對象,默認使用SerialExecutor(串行線程池),用於調度任務排隊順序執行。通過exec.execute(mFuture)開啟任務調度,當有任務執行時,其他任務等待。mTasks即ArrayDeque,它是一個雙端隊列。第一次添加任務時,mTasks.offer將新任務添加到任務隊列尾部,此時mActive這個Runnable為空,所以會直接走判斷是否為空中的scheduleNext方法,並在此方法中通過THREAD_POOL_EXECUTOR.execute(mActive)開啟執行任務。後續任務會走finally中的scheduleNext,此時mActive不為空。當執行r.run()方法,即調用瞭FutureTask對象的run方法
private static class SerialExecutor implements Executor { final ArrayDeque mTasks = new ArrayDeque(); Runnable mActive; public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } }
FutureTask對象的run方法如下,callable對象即是在構造FutureTask對象時傳入的mWorker,c.call()即在run方法中調用瞭mWorker的call方法,並將結果保存在result,call方法運行於子線程
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable c = callable; // callable對象即是在構造FutureTask對象時傳入的mWorker if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }
WorkerRunnable對象的call方法如下,它調用瞭doInBackground方法並將其返回值作為參數傳給postResult方法。到此調用瞭doInBackground方法,它運行在線程池中
public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); }
postResult方法,它會給AsyncTask內部的InternalHandler發送任務完成信息
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); message.sendToTarget(); return result; }
3. InternalHandler消息處理
InternalHandler如下,當消息類型為MESSAGE_POST_RESULT,通過finish方法完成執行結果的提交。當消息類型為MESSAGE_POST_PROGRESS時,回調更新進度onProgressUpdate方法。通過內部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; } } }
finish方法如下,當任務沒有取消時,調用onPostExecute,否則調用onCancelled。都運行在主線程
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
4. 進度更新
publishProgress,在doInBackground方法中調用,用以更新進度。此方法會向InternalHandler發送MESSAGE_POST_PROGRESS消息,以在UI線程更新進度
/** * This method can be invoked from {@link #doInBackground} to * publish updates on the UI thread while the background computation is * still running. Each call to this method will trigger the execution of * {@link #onProgressUpdate} on the UI thread. * * {@link #onProgressUpdate} will note be called if the task has been * canceled. * * @param values The progress values to update the UI with. * * @see #onProgressUpdate * @see #doInBackground */ protected final void publishProgress(Progress... values) { if (!isCancelled()) { sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult
(this, values)).sendToTarget(); } }
簡單案例
案例簡單模擬求和運算,並查看各個方法運行的線程
在MainActivity中自定義異步任務類繼承AsyncTask
class BackTask extends AsyncTask { @Override protected void onPreExecute() { Log.e("TAG", "onPreExecute-任務執行之前,當前線程:"+Thread.currentThread().getName()); super.onPreExecute(); } @Override protected Integer doInBackground(Integer... params) { Log.e("TAG", "doInBackground-任務執行中... ,當前線程:"+Thread.currentThread().getName()); int N = params[0]; int count = 0; int total = 0; // 計算總和 Integer progress = 0; // 進度 while (count < N) { ++count; total += count; progress = count * 100 / N; publishProgress(progress); } return total; } @Override protected void onPostExecute(Integer result) { super.onPostExecute(result); Log.e("TAG", "onPostExecute-執行結果,運算總和為" + result+" ,當前線程: "+Thread.currentThread().getName()); } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); Log.e("TAG", "onProgressUpdate-當前進度:" + values[0] + "%"+",當前線程:"+Thread.currentThread().getName()); } }
在onCreate方法中開啟任務
new BackTask().execute(100);
運行結果如下
09-07 08:33:53.508: E/TAG(2710): onPreExecute-任務執行之前,當前線程:main 09-07 08:33:53.508: E/TAG(2710): doInBackground-任務執行中... ,當前線程:AsyncTask #2 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:1%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:2%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:3%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:4%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:5%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:6%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:7%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:8%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:9%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:10%,當前線程:main ... ... ... ... (省略部分輸出) 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:90%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:91%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:92%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:93%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:94%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:95%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:96%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:97%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:98%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:99%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:100%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onPostExecute-執行結果,運算總和為5050 ,當前線程: main