簡(jiǎn)介
AsyncTask是一個(gè)輕量級(jí)的異步任務(wù)類,封裝了Handler和Thread,可以方便的在線程池里執(zhí)行后臺(tái)任務(wù),并把進(jìn)度和結(jié)果發(fā)送到主線程并在主線程中更新UI。AsyncTask應(yīng)該用來(lái)執(zhí)行比較短的后臺(tái)任務(wù),一般是以秒為單位的。如果需要保持線程長(zhǎng)期運(yùn)行,建議用線程池進(jìn)行。
一個(gè)AsyncTask是一個(gè)抽象的泛型類,通過(guò)繼承的方式來(lái)使用。AsyncTask需要指定三個(gè)三個(gè)泛型參數(shù)的類型,重寫四個(gè)回調(diào)方法。
三個(gè)泛型
三個(gè)泛型參數(shù)分別是Params, Progress and Result。
- Params:初始化AsyncTask時(shí)傳入的參數(shù)類型,用來(lái)定義傳遞給后臺(tái)任務(wù)的參數(shù)類型。
- Progress:后臺(tái)任務(wù)執(zhí)行進(jìn)度的類型。
- Result:后臺(tái)任務(wù)執(zhí)行完成返回的結(jié)果類型。
當(dāng)不需要相應(yīng)的參數(shù)的時(shí)候,也可定義成Void類型。
四個(gè)方法
- onPreExecute(),后臺(tái)任務(wù)執(zhí)行前在UI線程中調(diào)用,一般用來(lái)做一些初始化工作,比如顯示progress bar等。
- doInBackground(Params...),在onPreExecute()方法執(zhí)行之后,在后臺(tái)線程中調(diào)用,用來(lái)處理耗時(shí)的后臺(tái)任務(wù),執(zhí)行完成之后將結(jié)果return。在這個(gè)方法中可以調(diào)用publishProgress(Progress...)將執(zhí)行進(jìn)度發(fā)送到主線程的回調(diào)方法onProgressUpdate(Progress...)。
- onProgressUpdate(Progress...),在調(diào)用publishProgress(Progress...)方法之后會(huì)在主線程中回調(diào)這個(gè)方法。主要用來(lái)更新后臺(tái)任務(wù)的執(zhí)行進(jìn)度。
- onPostExecute(Result),在后臺(tái)任務(wù)執(zhí)行完成之后在UI線程中調(diào)用。后臺(tái)任務(wù)執(zhí)行結(jié)果會(huì)作為一個(gè)參數(shù)傳遞到這個(gè)方法中,一般用來(lái)更新UI。
取消任務(wù)
AsyncTask可以調(diào)用cancel(boolean)方法取消執(zhí)行,該方法調(diào)用之后,調(diào)用isCancelled()方法會(huì)返回true,后臺(tái)任務(wù)執(zhí)行完成后,不再調(diào)用onPostExecute(Object),而是調(diào)用onCancelled(Object)。為了盡快的取消任務(wù),應(yīng)該在doInBackground(Object[])方法中盡可能的調(diào)用isCancelled()判斷任務(wù)是否被取消。
使用方法
AsyncTask必須通過(guò)繼承的方式使用。子類至少?gòu)?fù)寫onInBackground(Params...)方法,一般還會(huì)復(fù)寫onPostExecute(Result)方法。如下使用一個(gè)模擬下載文件的例子:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
寫好子類之后,執(zhí)行就比較簡(jiǎn)單。
new DownloadFilesTask().execute(url1, url2, url3);
注意事項(xiàng)
AsyncTask使用有一些限制,需要注意:
- AsyncTask類必須在UI線程中加載。在Android4.1之后由系統(tǒng)自動(dòng)完成。
- AsyncTask實(shí)例必須在UI線程中創(chuàng)建。
- execute(Params...)方法必須在UI線程中調(diào)用。
- 不要手動(dòng)調(diào)用提供的四個(gè)回調(diào)方法。
- 每個(gè)AsyncTask實(shí)例只能執(zhí)行一次。
版本演化
AsyncTask類經(jīng)過(guò)幾次的版本演化,一開(kāi)始的AsyncTask是順序執(zhí)行的,從Android1.6開(kāi)始,改成了線程池,允許多個(gè)AsyncTask并行執(zhí)行。直到Android3.0開(kāi)始,為了避免并發(fā)引起的錯(cuò)誤,AsyncTask又改成默認(rèn)為順序執(zhí)行,但可以通過(guò)executeOnExecutor()方法并發(fā)執(zhí)行。
AsyncTask的工作原理
為了分析AsyncTask的工作原理,從execute(Params... params)方法入手。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
execute(Params... params)方法又調(diào)用了executeOnExecutor(Executor exec, Prams... 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();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
從上面的源碼可以看到,在AsyncTask執(zhí)行的時(shí)候,就調(diào)用了onPreExecute()方法,然后將params參數(shù)封裝成FutureTask對(duì)象,調(diào)用了線程池sDefaultExecutor的execute(mFuture)方法。線程池sDefaultExecutor實(shí)際就是一個(gè)串行的線程池,我們來(lái)看一下sDefaultExecutor線程池的實(shí)現(xiàn)。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
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中,F(xiàn)utureTask作為Runnable對(duì)象傳進(jìn)來(lái)之后,會(huì)把FutureTask插入任務(wù)隊(duì)列mTasks中,如果當(dāng)前沒(méi)有正在活動(dòng)的AsyncTask,就會(huì)調(diào)用sheduleNext()方法,如果有正在活動(dòng)的AsyncTask,則在執(zhí)行結(jié)束之后調(diào)用sheduleNext()方法,直到所有的任務(wù)執(zhí)行完成。可以看得出來(lái)SerialExecutor是串行執(zhí)行的。而真正執(zhí)行的線程池為THREAD_POOL_EXECUTOR,SerialExecutor是對(duì)THREAD_POOL_EXECUTOR的封裝。
在THREAD_POOL_EXECUTOR的execute()方法中最后調(diào)用了run方法。
public void run() {
...
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
...
}
而在FutureTask執(zhí)行run方法時(shí),會(huì)執(zhí)行Callable的call()方法,從AsyncTask的構(gòu)造方法中可以發(fā)現(xiàn),對(duì)應(yīng)的是mWorker的call()方法。
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) {
...
在call()方法中,執(zhí)行了doInBackground(mParams)方法,然后將返回值傳遞給postResult(result)中。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
而在postResult(Result)方法中,將result包裝成Message,發(fā)送給Handler,跟蹤getHandler()找到對(duì)應(yīng)的Handler為InternalHandler。
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;
}
}
}
InternalHandler收到MESSAGE_POST_RESULT消息之后,調(diào)用AsyncTask的finish()方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果AsyncTask取消執(zhí)行了,就調(diào)用onCancelled()方法,否則調(diào)用onPostExecute()方法。