我們在初學(xué)Android都用過AsyncTask 一個很方便用來請求網(wǎng)絡(luò)改變UI控件的類。面試官不多不少也會問到AsyncTask的內(nèi)容,下面來分析一下這個類內(nèi)部的邏輯。
AsyncTask說明
AsyncTask內(nèi)部封裝了Handler和Thread分別原來改變ui線程和在子線程做耗時操作。同時AsyncTask是一個抽象的泛型類
public abstract class AsyncTask<Params,Progress,Result>{}
- Params代表參數(shù)類型(doInBackground的參數(shù))通常是請求的url
- Progress代表進度類型(onProgressUpdate的參數(shù))通常是Integer
- Result代表結(jié)果返回類型(onPostExecute的參數(shù)),如果asynctask不需要傳遞參數(shù)就用Void來代替上述三個參數(shù)類型
AsyncTask 4個核心方法
- onPreExecute() 異步開始前會執(zhí)行該方法,用于顯示dialog
- doInBackground(Params... params) 在線程池執(zhí)行的異步任務(wù),在此方法內(nèi)調(diào)用publishProgress 傳入int進度值來更新進度,返回結(jié)果給onPostExecute,這里的省略號是可以傳入多個相同類型的參數(shù)。
- onPorgressUpdate(Progress... progress) 此方法在主線程執(zhí)行,當(dāng)任務(wù)發(fā)生進度改變就會調(diào)用此方法,比如顯示下載進度
- onPostExecute(Result... result) 主線程執(zhí)行,但異步方法執(zhí)行完就會調(diào)用的方法。傳入?yún)?shù)為doInBackground的返回值.
ps: 當(dāng)doInBackground的線程被取消就會回調(diào)給onCancelled這個方法,此方法被調(diào)用onPostExecute就不會調(diào)用了。
總結(jié):
- asynctask對象要在主線程創(chuàng)建,并調(diào)用execute方法
- 不能直接調(diào)用doinbackground方法
- 一個asynctask對象只執(zhí)行一次
- 3.0之前asynctask用并行線程池執(zhí)行,3.0后asynctask改用串行線程池,當(dāng)然你可以通過asynctask.executeOnExecutor來并行執(zhí)行任務(wù)
源碼入口execute
AsyncTask開始執(zhí)行的方法是在new AsyncTask().execute(url1),execute又調(diào)用了executeOnExetutor方法 傳入一個串行的線程池SDefaultExecutor和url參數(shù)。以下代碼:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
上面的sDefaultExecute就是new一個SerialExecute類
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
進入SerialExecutor類,我們看到這個類有個mTask 里面的Runnable會排隊執(zhí)行。并且判斷執(zhí)行完開始執(zhí)行下一個任務(wù)。
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);
}
}
}
接來下,回到executeOnExetutor 這個方法里面 我們可以看到一個mStatus來記錄當(dāng)前任務(wù)的狀態(tài),期間不斷改變狀態(tài)。
每個AsyncTask最先執(zhí)行onPreExecute方法,然后線程池exec.execute(mFuture);開始執(zhí)行。這里的mFuture就是一個Runnable
@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;
}
接著將mFuture傳入SerialExecutor的execute方法執(zhí)行,將之前的mFuture對象插入隊列mTask里面,判斷當(dāng)前有沒有任務(wù)在進行,沒活動就調(diào)用schedulNext方法執(zhí)行下一個asynctask任務(wù)。
Asynctask里面有2個線程池(一個用于排隊的serialexecutor和用于真正執(zhí)行任務(wù)的THREAD_POOL_EXECUTOR )和(負責(zé)線程調(diào)度的)internalHandler
然后在Asynctask的構(gòu)造方法 mWork會調(diào)用call方法將mTaskInvoked設(shè)置為true,再調(diào)用doinbackground 得到返回值再調(diào)用onpostexecute方法,
在postResult方法里面會發(fā)送message到sHandle來執(zhí)行finish task還是更新進度條,這里的finish有2種情況分別是調(diào)用onCancelled 和onPostexecute.
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;
}
};