淺談Android中AsyncTask的工作原理
概述
實際上,AsyncTask內部是封裝瞭Thread和Handler。雖然AsyncTask很方便的執行後臺任務,以及在主線程上更新UI,但是,AsyncTask並不合適進行特別耗時的後臺操作,對於特別耗時的任務,個人還是建議使用線程池。好瞭,話不多說瞭,我們先看看AsyncTask的簡單用法吧。
AsyncTask使用方法
AsyncTask是一個抽象的泛型類。簡單的介紹一下它的使用方式代碼如下:
package com.example.huangjialin.myapplication; import android.os.AsyncTask; import android.util.Log; public class AsyncTaskTest extends AsyncTask<String, Object, Long>{ @Override protected void onPreExecute() { super.onPreExecute(); Log.i("AsyncTaskTest","---準備下載---"); } @Override protected Long doInBackground(String... params) { Log.i("AsyncTaskTest","---在後臺正在下載---"); return null; } @Override protected void onProgressUpdate(Object... values) { super.onProgressUpdate(values); Log.i("AsyncTaskTest","---在更新---"); } @Override protected void onPostExecute(Long aLong) { super.onPostExecute(aLong); Log.i("AsyncTaskTest","---下載完成,將結果返回到主線程--"); } }
然後在activity中調用 new AsyncTaskTest().execute();就可以瞭…使用起來比較簡單,這裡就不在講述怎麼使用瞭。
AsyncTask的4個核心方法
1、onPreExecute():該方法在主線程中執行,在執行異步任務之前會被調用,一般用於一些準備工作。
2、doInBackground(String… params):這個方法是在線程池中執行,此方法用於執行異步任務。在這個方法中可以通過publishProgress方法來更新任務的進度,publishProgress方法會調用onProgressUpdate方法,另外,任務的結果返回給onPostExecute方法。
3、onProgressUpdate(Object… values):該方法在主線程中執行,主要用於任務進度更新的時候,該方法會被調用。
4、onPostExecute(Long aLong):在主線程中執行,在異步任務執行完畢之後,該方法會被調用,該方法的參數及為後臺的返回結果。
除瞭這幾個方法之外還有一些不太常用的方法,如onCancelled(),在異步任務取消的情況下,該方法會被調用。
好瞭,AsyncTask基本的使用就介紹到這裡,下面我們進入主題,我們一起看看AsyncTask的工作原理。
AsyncTask的工作原理
先從execute走起,源碼來瞭
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } @MainThread 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(); mWorker.mParams = params; exec.execute(mFuture); return this; }
為瞭方面分析,我就把英文註釋幹掉瞭…源碼可以知道從上面的execute方法內部調用的是executeOnExecutor()方法。而sDefaultExecutor實際上是一個串行的線程池。而onPreExecute()方法在這裡就會被調用瞭。接著看這個線程池。
private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); 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); } } } public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } }; 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 occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; }
從上面的代碼可以知道,AsyncTask的執行是排隊執行的,因為有關鍵字synchronized,而AsyncTask的Params參數就封裝成為FutureTask類,FutureTask這個類是一個並發類,在這裡它充當瞭Runnable的作用。接著FutureTask會交給SerialExecutor的execute方法去處理,而SerialExecutor的executor方法首先就會將FutureTask添加到mTasks隊列中,如果這個時候沒有任務,就會調用scheduleNext()方法,執行下一個任務。如果有任務的話,則執行完畢後最後在調用 scheduleNext();執行下一個任務。直到所有任務被執行完畢。而AsyncTask的構造方法中有一個call()方法,而這個方法由於會被FutureTask的run方法執行。所以最終這個call方法會在線程池中執行。而doInBackground這個方法就是在這裡被調用的。我們好好研究一下這個call()方法。
public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } }; private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
mTaskInvoked.set(true);表示當前任務已經執行過瞭。接著執行doInBackground方法,最後將結果通過postResult(result);方法進行傳遞。postResult()方法中通過sHandler來發送消息,sHandler的代碼如下:
private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } @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; } } } private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
註意:AsyncTask中有兩個線程池,一個是SerialExecutor,另一個是THREAD_POOL_EXECUTOR,其中前者主要是任務進行排隊的,後者才是真正的執行任務。
而AsyncTask中還有一個方法InternalHandler,這個方法的主要作用是將執行環境從線程池切換到主線程的。
以上就是淺談Android中AsyncTask的工作原理的詳細內容,更多關於Android中AsyncTask的工作原理的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Java使用Runnable和Callable實現多線程的區別詳解
- 解析Java異步之call future
- 一文徹底瞭解Android中的線程和線程池
- Java多線程 CompletionService
- android實現線程間通信的四種常見方式