AsyncTask是用來在實現在子線程執行任務後切換到UI線程,常見的比如下載任務的更新,執行下載後在UI線程實時更新進度條。由於是基本的API所以還是很有必要了解源碼的。
使用
使用其實也很簡單,主要是實現AsyncTask類,然後執行excute方法。其中有3個參數和4個方法是必須要掌握的。
private class MyAsyncTask extends AsyncTask<String, String, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
@Override
protected String doInBackground(String... strings) {
return null;
}
}
onPreExecute
這個方法是在UI線程執行,並且在後臺任務開始前執行。
doInBackground
這個在線程執行,這裏主要是做耗時任務。這個方法有參數和返回值,參數就是在調用execute傳進來的參數,返回值就是我們經過一些列操作後返回給onProgressUpdate方法的,主要用於UI的更新。例如我下載到50%然後同志UI實時更新。
onProgressUpdate
從方法名看就是更新進度,這個參數就是doInBackground中返回的。
onPostExecute
這個方法就是任務執行完成後要執行的方法。參數也是執行的結果。
三個參數
掌握了這4個方法,這三個參數就很容易理解了。
第一個,是傳入的參數。
第二個,是執行任務時進度更新的值。
第三個,任務執行結束的返回值。
源碼
其實源碼無非就是看內部的核心機制,和這幾個方法的調用流程。最直觀的就從execute方法開始。
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
這裏直接調用了executeOnExecutor,傳入了sDefaultExecutor和參數。
@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;
}
先看下這個函數裏面都做了什麼,在分析sDefaultExecutor。executeOnExecutor這個函數是public的所以我們也可以直接通過這個函數執行任務。如果我們通過executeOnExecutor()這個方法的話就要自己創建一個Executor,因爲默認的Executor是使用隊列維護同時只有一個線程執行任務,多任務時會被添加到隊列中,後面會講到。
首先,進來先判斷狀態,如果如果不是沒執行過的要拋出異常,這就是爲什麼如果執行兩次任務會報java.lang.IllegalStateException這個錯的原因。
其次,將狀態改爲正在執行。
然後,執行onPreExecute()方法,這就是爲什麼這個方法在主線程,而且在任務前執行。
再然後開始執行Executor的任務,這時候我們可以分析sDefaultExecutor了。
類裏可以看到
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
這兩個常量其實就是默認創建了一個Executor
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);
}
}
}
這個SerialExecutor裏面維護了一個隊列,然後通過offer()在隊列的末尾加入任務,通過poll()在頭部檢索出任務並刪除,檢索後賦值給mActive。因爲首次mActive爲null,所以加入了判斷mActive==null的時候執行scheduleNext(),後面再有任務來的話mActive就不是null了,所以是在runable中,通過finally調用了scheduleNext(),這時候就會等任務執行完成後在執行下一個任務。這就是上面說的爲什麼默認的SerialExecutor只能同時在一個線程執行任務。
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
這個主要就是通過各種默認爲的參數創建了一個線程池去執行任務。
這就是主要流程,但是在這個流程中還忽略了很多內容,在我們瞭解了整體框架流程後,在去填充我們想知道的細節,就更容易理解了。
首先看executeOnExecutor()方法中有兩個很重要的內容一個是mWorker和mFuture。其實執行任務的時候傳入了mFuture,而mFuture是一個mFutureTask真正執行的是mWorker。
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
this((Looper) null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
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);
}
}
};
}
在構造裏創建了三部分內容,mHandler、mWorker、mFutur
可以看到首先會創建handler因爲,線程通信還是需要依靠Handler。然後mWorker中主要就是執行doInBackground()然後將result傳給postResult。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
postResult主要就是通過handler發送一個what爲MESSAGE_POST_RESULT,obj爲result的message。
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
這時候看handleMessage是怎麼處理的。
這裏主要是調用區分what是完成還是未完成完成的話就是調用finish方法,未完成就是onProgressUpdate方法,
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
在看finish方法就是判斷是否取消然後調用onPostExecut方法將結果傳入。
hadlerMessage還處理一個就是更新進度,那這個message是在哪裏發的呢?
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
可以看到是通過publishProgress這個方法,所以我們如果需要更新進度的話要自己在doInBackground這個方法裏調用publishProgress()方法傳入進度。然後在纔會在onProgressUpdate()這個方法中收到。
總結
至此 整個流程也就清晰了,這四個方法是分別在哪裏調用的在能實現異步然後更新UI的功能,其實原理很簡單,就是用了一個線城池然後我們在子線程實時通過Handler發送Message到UI線程中執行進度的任務,默認通過一個隊列維護任務,也可以自定義Executor來實現多線程執行任務。