AsyncTask簡介
- AsyncTask,是android提供的輕量級的異步類,可以直接繼承AsyncTask,在類中實現異步操作,並提供接口反饋當前異步執行的程度(可以通過接口實現UI進度更新),最後反饋執行的結果給UI主線程。
- AsyncTask實際上就是封裝了Thread和Handler,可以讓我們在後臺進行計算並且把計算的結果及時更新到UI上,而這些正是Thread+Handler所做的事情,AsyncTask的作用就是簡化Thread+Handler
- 在1.6之前,AsyncTask是串行執行任務的,1.6的時候AsyncTask開始採用線程池裏處理並行任務,但是從3.0開始,爲了避免AsyncTask所帶來的併發錯誤,AsyncTask又採用一個線程來串行執行任務
AsyncTask步驟
一個異步任務的執行一般包括以下幾個步驟:
1.execute(Params… params):
執行一個異步任務,需要我們在代碼中調用此方法,觸發異步任務的執行。
2.onPreExecute():
在execute(Params…params)被調用後立即執行,一般用來在執行後臺任務前對UI做一些標記。在主線程中執行。
3.doInBackground(Params…params):
在onPreExecute()完成後立即執行,用於執行較爲費時的操作,此方法將接收輸入參數和返回計算結果。在執行過程中可以調用publishProgress(Progress…values)來更新進度信息。在線程池中執行。
4.onProgressUpdate(Progress…values):
在調用publishProgress(Progress…values)時,此方法被執行,直接將進度信息更新到UI組件上。 在主線程中執行。
5.onPostExecute(Result result):
當後臺操作結束時,此方法將會被調用,計算結果將做爲參數傳遞到此方法中,直接將結果顯示到UI組件上。在主線程中執行。
注意事項
1.異步任務的實例必須在UI線程中創建。
2.AsyncTask的類必須在UI線程加載(從4.1開始系統會幫我們自動完成)
3.execute(Params… params)方法必須在UI線程中調用。
4.不要在你的程序中去直接調用onPreExecute(), onPostExecute, doInBackground, onProgressUpdate方法
一個AsyncTask對象只能執行一次,即只能調用一次execute方法,否則會報運行時異常
5.不能在doInBackground(Params… params)中更改UI組件的信息。
6.一個AsyncTask對象只能執行一次,即只能調用一次execute方法,否則會報運行時異常
7.AsyncTask不是被設計爲處理耗時操作的,耗時上限爲幾秒鐘,如果要做長耗時操作,強烈建議你使用Executor,ThreadPoolExecutor以及FutureTask
8.在1.6之前,AsyncTask是串行執行任務的,1.6的時候AsyncTask開始採用線程池裏處理並行任務,但是從3.0開始,爲了避免AsyncTask所帶來的併發錯誤,AsyncTask又採用一個線程來串行執行任務
AsyncTask工作原理
AsyncTask啓動首先會調用execute,先從execute方法開始分析,execute又會調用executeOnExecutor,它們的實現如下:
@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;
}
sDefaultExecutor實現了一個串行的線程池,一個進程中所有的AsyncTask都會在這個線程池中排隊。onPreExecute會先執行。然後通過exec.execute(mFuture)執行這個線程池。
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
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 occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
首先系統會把AsyncTask的mParams參數封裝爲FutureTask對象,FutureTask是一個併發類。接着這個FutureTask會交給SerialExecutor的execute方法去處理,execute首先會把FutureTask插入任務隊列mTasks,詳細實現如下:
/*串行執行器的實現,我們要好好看看,它是怎麼把並行轉爲串行的
*目前我們需要知道,asyncTask.execute(Params ...)實際上會調用
*SerialExecutor的execute方法,這一點後面再說明。也就是說:當你的asyncTask執行的時候,
*首先你的task會被加入到任務隊列,然後排隊,一個個執行
*/
private static class SerialExecutor implements Executor {
//線性雙向隊列,用來存儲所有的AsyncTask任務
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
//當前正在執行的AsyncTask任務
Runnable mActive;
public synchronized void execute(final Runnable r) {
//將新的AsyncTask任務加入到雙向隊列中
mTasks.offer(new Runnable() {
public void run() {
try {
//執行AsyncTask任務
r.run();
} finally {
//當前AsyncTask任務執行完畢後,進行下一輪執行,如果還有未執行任務的話
//這一點很明顯體現了AsyncTask是串行執行任務的,總是一個任務執行完畢纔會執行下一個任務
scheduleNext();
}
}
});
//如果當前沒有任務在執行,直接進入執行邏輯
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
//從任務隊列中取出隊列頭部的任務,如果有就交給併發線程池去執行
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
SerialExecutor實現了AsyncTask的排隊過程。ArrayDeque 類提供了可調整大小的陣列,並實現了Deque接口。從任務隊列中取出隊列頭部的任務,如果有就交給併發線程池HREAD_POOL_EXECUTOR去執行。
THREAD_POOL_EXECUTOR線程池用於真正執行任務。
//獲取當前的cpu核心數
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//線程池核心容量
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//線程池最大容量
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//過剩的空閒線程的存活時間
private static final int KEEP_ALIVE = 1;
//ThreadFactory 線程工廠,通過工廠方法newThread來獲取新線程
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
//原子整數,可以在超高併發下正常工作
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
//靜態阻塞式隊列,用來存放待執行的任務,初始容量:128個
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
/**
* 靜態併發線程池,可以用來並行執行任務,儘管從3.0開始,AsyncTask默認是串行執行任務
* 但是我們仍然能構造出並行的AsyncTask
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
WorkerRunnable的call()方法最終會在線程池中執行,如下
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mTaskInvoked.set(true),表示當前任務已經被調用,然後執行doInBackground方法,接着返回值傳遞給postResult()方法,如下:
//doInBackground執行完畢,發送消息
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
postResult會通過sHandler發送一個MESSAGE_POST_RESULT的消息。sHandler實現如下:
//AsyncTask內部Handler,用來發送後臺計算進度更新消息和計算完成消息
private static class InternalHandler extends Handler {
@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;
}
}
}
sHandler收到MESSAGE_POST_RESULT後會調用finish方法,如果被取消任務,就調用onCancelled,否則調用onPostExecute:
//任務結束的時候會進行判斷,如果任務沒有被取消,則onPostExecute會被調用
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
解決3.0以上版本不能並行執行的問題
直接調用executeOnExecutor:
new MyAsyncTask(“AsyncTask#1”).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,”“);