從原始碼分析AsyncTask
AsyncTask是Android提供的一個非同步處理的方式。該方式使用較為方便,與Handler相比在程式碼上顯得更簡潔。
先來看看使用AsyncTask常用到的幾個方法:
1.execute(Params… params),執行一個非同步任務,需要我們在程式碼中呼叫此方法,觸發非同步任務的執行。(在UI執行緒呼叫)
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元件上。
詳細的例子網上也很多了,此處不再列舉,以上也是引用的別人的部落格所述。
地址:http://blog.csdn.net/liuhe688/article/details/6532519 。
此篇主要是根據原始碼來分析AsyncTask的原理。
AsyncTask原始碼分析
老套路,先看看AsyncTask的建構函式。
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
//WorkerRunnable 為一個繼承Callable<Result>介面的虛類
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//呼叫doInBackground 但並不在這開始執行
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {//初始化mFuture
@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);
}
}
};
}
在建構函式中進行了一些初始化工作,並且最後都呼叫到了postResult,在postResultIfNotInvoked(get())中,其實最後也呼叫到了postResult。 這裡用到了
Java併發程式設計:Callable、Future和FutureTask。有興趣的可以看看。
在上面的程式碼中,當mWorker中定義的call方法被執行時,doInBackground就會開始執行,我們定義的後臺任務也就真正開始了。實際上mFuture物件封裝了call方法,當mFuture物件被提交到AsyncTask包含的執行緒池執行時,call方法就會被呼叫,我們定義的後臺任務也就開始執行了。到此,我們先記住要使doInBackground()方法執行,就需要mFuture被執行,但是執行的地方還沒找到。回想我們使用AsyncTask的時候,需要呼叫execute()方法,讓程式跑起來。拿我們就先看看這個方法。
&emp;我們建立一個繼承於一個public abstract class AsyncTask
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
來看看executeOnExecutor方法 和sDefaultExecutor,params引數是一直傳到doInBackground方法的。
sDefaultExecutor是什麼呢?通過程式碼可以找到
public static final Executor SERIAL_EXECUTOR = Utils.hasHoneycomb() ? new SerialExecutor() :
Executors.newSingleThreadExecutor(sThreadFactory);
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
sDefaultExecutor 要不是一個 SerialExecutor要不就是一個單執行緒池。來看看SerialExecutor到底是什麼。
private static class SerialExecutor implements Executor {
//mTasks 快取佇列
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);// 執行任務
}
}
}
從上面的程式碼,可以看出首先由一個快取佇列mTasks ,該佇列通過offer新增任務,通過THREAD_POOL_EXECUTOR.execute(mActive)去執行任務。那麼接下來就是THREAD_POOL_EXECUTOR了。
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory,
new ThreadPoolExecutor.DiscardOldestPolicy());
很明顯了THREAD_POOL_EXECUTOR就是一個執行緒池,並且規定了CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,TimeUnit.SECONDS等。從原始碼中也可以看到
private static final int CORE_POOL_SIZE = 5;執行緒池大小5
private static final int MAXIMUM_POOL_SIZE = 128;最大執行緒數128
private static final int KEEP_ALIVE = 1;存活時間1s
接下來就是executeOnExecutor方法了。
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();//該方法被呼叫,一般用來在執行後臺任務前對UI做一些標記。
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
在程式碼的倒數第二行exec.execute(mFuture);這個方法。還記得之前mFuture物件麼,這就是他被執行的地方了。從而doInBackground方法也就能夠執行了,而且還由執行緒池進行控制。
以上為AsyncTask 呼叫流程的理解。