簡(jiǎn)介:AsyncTask是Android中用于異步操作的類。盡管現(xiàn)在已經(jīng)逐漸被強(qiáng)調(diào)舍棄,不過(guò)就源碼來(lái)說(shuō),AsyncTask還是一個(gè)挺不錯(cuò)的設(shè)計(jì)。鑒于上一篇文章非墨研究過(guò)線程池<a href="http://www.itdecent.cn/p/10da5cc92caa"> 線程池源碼分析</a>,正好以AsyncTask作為第二篇線程池相關(guān)的研究對(duì)象。
廢話不多說(shuō),我們先來(lái)看下,我們?cè)俅a中如何使用一個(gè)AsyncTask:
// demo1
new AsyncTask<String, Integer, String>() {
protected void onProgressUpdate(Integer[] values) {
//TODO process update in UI Thread
};
protected void onPostExecute(String result) {
//TODO on Execute finish
};
@Override
protected String doInBackground(String... params) {
int i = 0;
while (i <= 100) {
//todo something
this.publishProgress(i);// notify progress change
i ++;
}
return "result";
}
}.execute("params1","params2");
demo1是比較常見(jiàn)的做法,生成了一個(gè)AsyncTask對(duì)象,然后通過(guò)執(zhí)行execute方法。我們可以從demo1得到下面的結(jié)論:
1.execute方法里面需要傳入不定個(gè)數(shù)的參數(shù),參數(shù)的類型由AsyncTask的第二個(gè)泛型參數(shù)指定。如果你想指定多種類型的參數(shù),可以將你的類型做頂層抽象,或者是將多種參數(shù)封裝到一個(gè)新的類型里面,然后從這個(gè)類里面取。
2.在AsyncTask里面,一般以“on”打頭的方法都是在UI線程中執(zhí)行(其實(shí)并不準(zhǔn)確,實(shí)際上如果你的線程中存有Looper都可以使用)。
其實(shí)不管是在Android或者java,跟線程池或者線程相關(guān)的執(zhí)行動(dòng)作,常常都被命名成為execute。我們姑且有個(gè)印象,AsyncTask里面或許用到了線程池。我們來(lái)看下AsyncTask的具體源碼:
//code2
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;
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());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
正如code2代碼所示,我們上面方法名的假設(shè)并沒(méi)有錯(cuò),AsyncTask用了線程池,并且核心線程數(shù)量按照cpu的數(shù)量+1給出,最大線程數(shù)量按照2倍的cpu數(shù)量+1給出。至于為什么按照這個(gè)給值,非墨不得而知,這種數(shù)值或許是最優(yōu)解,但是為什么是最優(yōu)解呢?如果非墨得到了答案,非墨會(huì)在后續(xù)的文章中說(shuō)明。在這里,線程池被定義為常量,我們可以斷言,所有的AsyncTask都是共享線程池的。
//code3
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
//線性執(zhí)行隊(duì)列
private static final int MESSAGE_POST_RESULT = 0x1;//post結(jié)果消息
private static final int MESSAGE_POST_PROGRESS = 0x2;//進(jìn)度消息
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private final WorkerRunnable<Params, Result> mWorker;//執(zhí)行對(duì)象
private final FutureTask<Result> mFuture;//worker的一個(gè)裝飾對(duì)象,用于線程池操作
private volatile Status mStatus = Status.PENDING;
private final AtomicBoolean mCancelled = new AtomicBoolean();
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
code3代碼里,定義了一個(gè)線性的執(zhí)行隊(duì)列,還有返回消息函數(shù),已經(jīng)一個(gè)工作對(duì)象worker,以及其包裝對(duì)象Future。用Status枚舉類型來(lái)記錄AsyncTask的狀態(tài)。用兩個(gè)原子變量mCancelled和mTaskInvoked來(lái)標(biāo)記攔截一些操作。
//code3
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
在AsyncTask的構(gòu)造器里,生成了他的工作Worker對(duì)象和和Future對(duì)象。mWorker是一個(gè)WorkerRunnable類,它實(shí)現(xiàn)了java.util.concurrent.Callable接口。這點(diǎn)在非墨上篇的線程池分析中并沒(méi)有提及,但是萬(wàn)變不離其總,Callable接口對(duì)象最終一樣會(huì)包裝成為一個(gè)Runnable對(duì)象。而這種包裝的方式,需要一個(gè)叫做FutureTask的類來(lái)完成。這就是我們的mFuture對(duì)象。我們不妨回到我們的線程池相關(guān)代碼:
// code AbstractExecutorService.java
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
...
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
線程池使用Callable接口需要調(diào)用submit方法,在submit的代碼中,會(huì)將你的Callable對(duì)象包裝成為一個(gè)RunnableFuture對(duì)象。而RunnableFuture就實(shí)現(xiàn)了我們上篇所說(shuō)的Runnable接口。FutureTask是這個(gè)接口的真正實(shí)現(xiàn)類。這個(gè)類的主要工作是為run方法做裝飾。
// code FutureTask.java run()
public void run() {
if (state != NEW ||!U.compareAndSwapObject(this, RUNNER, null,Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
....
}
}
從代碼上看,FutureTask在實(shí)現(xiàn)的時(shí)候,使用了CAS算法來(lái)保證原子性。實(shí)現(xiàn)方式是使用了UnSafe類。注入了當(dāng)前的運(yùn)行線程。之后調(diào)用Callable的call方法來(lái)獲取返回值。然后通過(guò)set方法來(lái)設(shè)置你的result。
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
U.putOrderedInt(this, STATE, NORMAL); // final state
finishCompletion();
}
}
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
在FutureTask通過(guò)調(diào)用set來(lái)設(shè)置返回值了以后,另外一個(gè)線程通過(guò)調(diào)用get方法來(lái)獲取執(zhí)行結(jié)果。get方法在awaitDone的時(shí)候?qū)?zhí)行CAS操作阻塞。那么我們基于以上的理解,回到我們剛才的code3 AsyncTask 的構(gòu)造器代碼。
mFuture復(fù)寫了FutureTask的done方法,主要是為了處理當(dāng)你的AsyncTask沒(méi)有執(zhí)行的時(shí)候,默認(rèn)的返回值。我們構(gòu)造完AsyncTask了以后,接下去就要執(zhí)行它的execute方法。而execute方法內(nèi)部會(huì)調(diào)用到executeOnExecutor()方法。
-executeOnExecutor包含兩個(gè)種類型的參數(shù),這一種是Executor 變量,一般情況下指的是我們上面說(shuō)的線性執(zhí)行隊(duì)列SERIAL_EXECUTOR,第二種類型就是你傳入的參數(shù)列表。
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();//執(zhí)行前回調(diào)
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
在AsyncTask執(zhí)行executeOnExecutor將回調(diào)onPreExecute方法,然后將參數(shù)列表注入到mWorker對(duì)象中。onPreExecute 是個(gè)空的protected方法。因此,這個(gè)回調(diào)是在當(dāng)前調(diào)用線程中執(zhí)行的。
當(dāng)SERIAL_EXECUTOR.execute的時(shí)候,mFuture對(duì)象將會(huì)拋給共享線程池的execute 方法:
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
當(dāng)mFuture處理完結(jié)果以后,將通過(guò)postResult方法將結(jié)果拋給Handler所在的線程。實(shí)際上在Handler里面定義了兩個(gè)消息
1.private static final int MESSAGE_POST_RESULT = 0x1;
2. private static final int MESSAGE_POST_PROGRESS = 0x2;
分別用于返回結(jié)果到Handler所在線程,已經(jīng)發(fā)布進(jìn)度。發(fā)布進(jìn)度的消息可以調(diào)用publicProgress發(fā)送出去。我們來(lái)看下Result消息的處理:
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;
}
消息處理將調(diào)用AsyncTask.finish方法。這個(gè)方法里面,將根據(jù)當(dāng)前task的狀態(tài)回調(diào)onCancelled方法,或者onPostExecute方法。這就是我們熟知的東西。要記住,這里面的回調(diào)方法,是在Handler所在的線程,一般是Ui線程中執(zhí)行。那么這個(gè)Handler所在的線程是不是在Ui線程呢?
private static final InternalHandler sHandler = new InternalHandler();
AsyncTask使用一個(gè)靜態(tài)成員變量來(lái)標(biāo)記使用的Handler,那么這個(gè)Handler所在的線程就是第一次加載該類的那個(gè)線程。那么第一次加載該類是在什么地方呢?我們知道,所有的Android進(jìn)程都是運(yùn)行在Davik的虛擬機(jī)上的,這個(gè)虛擬機(jī)的入口是ActivityThread類。這個(gè)類運(yùn)行的線程就是我們熟悉的UI線程。
//code ActivityThread.main
...
AsyncTask.init();
...
我們看到,在這個(gè)進(jìn)程剛開(kāi)始啟動(dòng),還沒(méi)進(jìn)入消息循環(huán)的時(shí)候,主進(jìn)程堆棧里,已經(jīng)對(duì)AsyncTask進(jìn)行了初始化的操作,這里面調(diào)用了AsyncTask的init方法:
/** @hide Used to force static handler to be created. */
public static void init() {
sHandler.getLooper();
}
當(dāng)然這種調(diào)用沒(méi)有任何的實(shí)際的邏輯意義,就像注釋說(shuō)的,只是為了讓Handler生成而已。這樣,實(shí)際上我們對(duì)AsyncTask本身已經(jīng)分析的差不多了,最后一個(gè)小問(wèn)題就是:既然AsyncTask里面用到Future的模式,那AsyncTask是否Future的特性的。這是當(dāng)然的,AsyncTask里面提供了get接口,里面調(diào)用了Future的get接口,相當(dāng)于有了Future的特性:
public final Result get() throws InterruptedException, ExecutionException {
return mFuture.get();
}
好的,更多的功能,更多的特性就讓各位看官自己發(fā)掘吧。
——非墨