1、概述
AsyncTask是一個輕量級的異步任務類,并可以將結果與執行進度實時傳遞給主線程,讓主線程進行UI更新。
2、相關參數與方法
- public abstract class AsyncTask<Params,Progress,Result>。三個泛型參數分別代表了參數值類型,進度類型,返回結果類型。
- onPreExecute(),在主線程中執行,在異步任務開始之前調用。
- doInBackground(Params...params),在線程池中執行,用來進行異步任務。
- publishProgress(Progress... values),可以在doInBackground方法中進行調用來通知主線程中更新進度的方法,來進行進度更新
- onProgressUpdate(Progress... values) ,主線程中更新進度的方法。用來更新UI中的進度
- onPostExecute(Result result),當正常完成的時候,調用的方法,此方法也在主線程中執行。
- onCancelled(),當任務被取消的時候此方法會被調用,onPostExecute方法不會被調用。
3、基本使用
任務所需參數類型為String,進度類型為Integer,返回結果類型為String
class MyAsyncTask extends AsyncTask<String,Integer,String>{
@Override
protected void onPreExecute() {
super.onPreExecute();
//Todo:做一些準備與初始化操作。
}
@Override
protected String doInBackground(String... strings) {
//Todo:異步任務
//Todo:通知進度
publishProgress(10);
if (isCancelled()){
//Todo:判斷任務是否被取消掉了,如果被取消掉了,就停止異步任務
return "";
}
//返回結果
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//Todo:得到進度并更新UI
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//Todo:任務完成之后會進行調用。如果任務被取消將不會調用此方法。
}
@Override
protected void onCancelled() {
super.onCancelled();
//Todo:任務被取消之后會進行調用。
}
}
//創建實例對象并使用execute開始任務,參數為處理任務所要參數。
new MyAsyncTask().execute("www.baidu.com");
4、原理分析
- 首先我們來看一下AsyncTask的構造方法
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
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);
}
}
};
}
- 從27的AsyncTask源碼中我們可以看出:第一步:AsyncTask有三個構造方法,最終都會調用AsyncTask(@Nullable Looper callbackLooper)這個構造方法,首先AsyncTask會初始化一個Handler用來處理消息,而默認情況下,會拿我們主線程的looper構建我們的Handler,所以我們所有的消息處理都是在主線程當中的。
- 第二部,AysncTask將我們參數與返回值封裝成一個WorkerRunnable對象,又將WorkerRunnable封裝為FutureTask(執行在線程中的Runnable),FutureTask中的run方法會調用WorkerRunnable的Call方法,在任務執行的時候(在線程池中被子線程)被調用,mTaskInvoked會設置為true表示任務已經執行,然后調用doInBackgroud方法傳入參數并返回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;
}
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;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
通過pstResult的源碼我們可以看出。使用了Handler發送了一個消息,而我們的Handler在默認構造的時候是InternalHandler 。可以看到處理MESSAGE_POST_RESULT的時候調用的finish方法,判斷是否是被取消,如果被取消就調用onCancelled方法,如果沒有被取消調用onPostExecute方法, 所以onCancellde和onPostExecute方法都是在主線程中執行的。
- 接下來我們來分析任務是怎么異步進行的。我們從execute方法來分析。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, 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;
}
execute方法調用了executeOnExecutor方法。在這個方法中我們可以看到首先調用onPreExecute()方法;此方法會在AsyncTask.execute方法調用的線程中執行。最先執行的方法。然后調用exec.execute(mFuture)方法,exec是一個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);
}
}
}
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;
}
從它的源碼中我們可以看出,他是一個線程池。但是他里面只有一個存放任務的ArrayDeque隊列。在execute方法中用offer方法把任務加到隊列當中,如果沒有任務在執行的話就調用scheduleNext方法執行任務,而當任務完成之后如果還有任務,還會調用這個方法繼續執行,從這里我們可以看出AsyncTask方法是串行執行任務的。我們在scheduleNext方法中可以看到其調用了THREAD_POOL_EXECUTOR的execute方法執行任務,而THREAD_POOL_EXECUTOR是一個線程池。所以這里才是真正執行任務的線程池。
對于publishProgress和onProgressUpdate這兩個方法的源碼大家可以自己看一下,只是用了handler將消息發送到主線程而已,源碼比較簡單。
5、各版本中的差異
在Android1.6之前AsyncTask是串行執行任務的,在1.6的時候修改成了線程池并行處理任務,但是從3.0開始,為了避免并發錯誤,又改為用一個線程串行執行任務,但是保留了executeOnExecutor方法來并行的執行任務,參數為THREAD_POOL_EXECUTOR。