今天來分析一下AsyncTask羡玛,并開始嘗試閱讀Google源碼工程師寫的文檔.全英文,顯然是一項(xiàng)挑戰(zhàn)一睁,來吧钻弄。因?yàn)橹耙矝]寫過源碼分析的文章,看的也比較少者吁,所以如果結(jié)構(gòu)混亂窘俺,原諒我不是故意的。
AsyncTask源碼在源碼目錄的framework/base/core/java/android/os目錄下复凳,在具體代碼之前瘤泪,有詳細(xì)的英文說明文檔。這篇文章就出自此處染坯。
一均芽、說明
AsyncTask是Anroid系統(tǒng)提供給我們的在UI線程中使用該類,來進(jìn)行執(zhí)行后臺(tái)執(zhí)行長(zhǎng)時(shí)間的操作单鹿,并將執(zhí)行結(jié)果更新到UI線程中;是除了使用Thread和Handler來實(shí)現(xiàn)耗時(shí)操作和結(jié)果更新的另一種實(shí)現(xiàn)深纲,更簡(jiǎn)單仲锄,方便劲妙。
- 定義說明:定義一個(gè)異步的AsyncTask任務(wù)時(shí),系統(tǒng)允許傳遞3個(gè)屬性類型來進(jìn)行說明儒喊,Params镣奋,Progress,Result;按其執(zhí)行順序依次對(duì)應(yīng)怀愧,執(zhí)行前需傳入的參數(shù)侨颈,執(zhí)行中進(jìn)度的更新單位,執(zhí)行完成之后返回的結(jié)果類型芯义;使用時(shí)可傳入String哈垢,Long,Integer等類型的參數(shù)扛拨,如果不需要參數(shù)耘分,使用時(shí)可傳Void。
- 執(zhí)行過程說明:AsyncTask執(zhí)行的過程主要設(shè)計(jì)開發(fā)者的就是4個(gè)方法绑警,也可以理解為4步:依次為onPreExecute求泰,doInBackground,onProgressUpdate计盒,onPostExecute渴频。其中只有doInBackground方法是在非UI線程中執(zhí)行的,其他三個(gè)均在UI線程中執(zhí)行北启,極大的方便了開發(fā)者的使用卜朗。
二、用法
AsyncTask類在源碼中被定義成了抽象類暖庄,如果開發(fā)者想要使用AsyncTask,必須要自己實(shí)現(xiàn)一個(gè)自定義任務(wù)類來extends源碼聊替,然后進(jìn)行使用。自定義任務(wù)類應(yīng)至少實(shí)現(xiàn)doInBackground方法培廓,因?yàn)槠涫浅殚e的惹悄。通常的情況下,還會(huì)實(shí)現(xiàn)onPostExecute方法肩钠,onPreExecute方法等泣港。
舉例:
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");
}
}
一旦一個(gè)任務(wù)被創(chuàng)建,開始執(zhí)行該任務(wù)价匠,僅需調(diào)用其execute方法即可執(zhí)行当纱。
- 執(zhí)行任務(wù)實(shí)例,執(zhí)行任務(wù)分為串行和并行兩種形式踩窖,如下:
new DownAsyncTask().extcute();//串行實(shí)例化
new DownAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");//并行實(shí)例化
- 取消一個(gè)任務(wù):一個(gè)任務(wù)可以在執(zhí)行期間的任何時(shí)刻被取消坡氯,只需要調(diào)用其cancel方法,調(diào)用cancel方法之后,isCancelled方法就會(huì)返回true箫柳,表示該任務(wù)已取消手形;在調(diào)用cancel方法之后,doInBackground方法結(jié)束執(zhí)行之后悯恍,會(huì)調(diào)用onCancelled方法库糠,不在執(zhí)行onPostExecute方法;
三涮毫、使用規(guī)則謹(jǐn)記
- 目標(biāo)任務(wù)必須在UI線程中進(jìn)行加載瞬欧;
- 目標(biāo)任務(wù)實(shí)例必須在UI線程中進(jìn)行創(chuàng)建;
- 開發(fā)者不能手動(dòng)調(diào)用onPreExecute罢防,onPostExecute艘虎,doInBackground,onProgressUpdate方法篙梢;
- 目標(biāo)任務(wù)僅僅會(huì)執(zhí)行一次顷帖,如果試圖執(zhí)行多次,系統(tǒng)會(huì)拋出異常
四渤滞、執(zhí)行規(guī)則
- 起初剛開始設(shè)計(jì)時(shí)贬墩,AsyncTask僅會(huì)在后臺(tái)單獨(dú)的線程中進(jìn)行執(zhí)行,也就是說執(zhí)行是串行的;
- 從SDK1.6開始妄呕,開始轉(zhuǎn)變?yōu)樵谝粋€(gè)線程池中允許多個(gè)任務(wù)進(jìn)行請(qǐng)求執(zhí)行,也就是支持并行執(zhí)行陶舞;
- 從3.1開始,又修改為目標(biāo)任務(wù)在一個(gè)單線程中執(zhí)行绪励,也就是串行執(zhí)行肿孵,主要是為了避免并發(fā)執(zhí)行可能會(huì)造成的錯(cuò)誤;如果實(shí)在想并發(fā)執(zhí)行疏魏,可以調(diào)用executeOnExecutor方法進(jìn)行停做;
以上的內(nèi)容均來在AsyncTask源碼聲明文件前的注釋,從中也可以看到大莫,人家Google確實(shí)是偉大的公司蛉腌,標(biāo)準(zhǔn)規(guī)范特別詳細(xì),特別貼心只厘。
五烙丛、代碼分析
- 關(guān)于線程池的配置
//獲取到當(dāng)前設(shè)備的cpu配置
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心線程數(shù)量 動(dòng)態(tài)的計(jì)算
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//線程池中允許的最大線程數(shù)目
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
- 關(guān)于任務(wù)狀態(tài)
一個(gè)目標(biāo)任務(wù)在其完整的生命周期內(nèi),其任意時(shí)刻的狀態(tài)僅會(huì)是一下三種中的一種:
public enum Status {
//任務(wù)未執(zhí)行
PENDING,
//任務(wù)正在執(zhí)行中
RUNNING,
//任務(wù)已結(jié)束
FINISHED,
}
- 構(gòu)造函數(shù)中的初始化工作
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
//設(shè)置線程的優(yōu)先級(jí)
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//調(diào)用doInBackground方法,并將postResult進(jìn)行回傳分發(fā)
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
//任務(wù)執(zhí)行完畢后會(huì)調(diào)用done方法
@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);
}
}
};
}
//初始化操作中涉及到的mWorker變量的類聲明,該WorkerRunnable實(shí)現(xiàn)了Callable接口羔味,使用時(shí)實(shí)現(xiàn)call方法
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
//初始化操作中涉及到的get()方法河咽,該方法返回的就是執(zhí)行后的結(jié)果,也就是mWorker的call方法的返回值
public final Result get() throws InterruptedException, ExecutionException {
return mFuture.get();
}
- 執(zhí)行過程分析
1在主線程中實(shí)例化任務(wù)對(duì)象并顯示調(diào)用execute方法。
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
* 全局的線程池用來執(zhí)行隊(duì)列任務(wù)
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//This method must be invoked on the UI thread.方法注釋說明該方法必須在UI線程調(diào)用
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
//調(diào)用executeOnExecutor方法執(zhí)行后臺(tái)任務(wù)
return executeOnExecutor(sDefaultExecutor, params);
}
2.執(zhí)行線程池對(duì)象的execute方法赋元,具體執(zhí)行某一個(gè)隊(duì)列任務(wù).
//包含兩個(gè)參數(shù)忘蟹,第一個(gè)參數(shù)為默認(rèn)的線程池對(duì)象飒房,默認(rèn)已經(jīng)初始化;第二個(gè)參數(shù)為具體任務(wù)的傳入?yún)?shù)
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//執(zhí)行之前首先判斷任務(wù)的狀態(tài)寒瓦,只有是PENDING狀態(tài)才能執(zhí)行情屹,這里也照應(yīng)了前文說的坪仇,一個(gè)目標(biāo)任務(wù)只能被執(zhí)行一次杂腰,否則會(huì)拋出異常;
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)");
}
}
//將目標(biāo)任務(wù)的狀態(tài)設(shè)置為正在執(zhí)行
mStatus = Status.RUNNING;
//調(diào)用onPreExecute方法椅文,注意此時(shí)還在UI線程中
onPreExecute();
//將任務(wù)傳入?yún)?shù)進(jìn)行賦值喂很,調(diào)用execute方法執(zhí)行耗時(shí)操作;同時(shí)返回為AsyncTask對(duì)象任務(wù)自身皆刺;
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
3.具體的execute方法
//變量定義
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//Executor 聲明及實(shí)現(xiàn)
private static class SerialExecutor implements Executor {
//任務(wù)線程隊(duì)列
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
//上一步驟提到的execute方法少辣,參數(shù)說明傳入一個(gè)Runnable對(duì)象
public synchronized void execute(final Runnable r) {
//將此任務(wù)添加到任務(wù)隊(duì)列中
mTasks.offer(new Runnable() {
public void run() {
try {
//此處調(diào)用的run方法就是調(diào)用的傳入的mFuture對(duì)象的run方法
r.run();
} finally {
//try...finally代碼塊,finally塊一定會(huì)執(zhí)行,處理隊(duì)列中的下一個(gè)任務(wù)
scheduleNext();
}
}
});
//如果沒有活動(dòng)的runnable羡蛾,從雙端隊(duì)列里面取出一個(gè)runnable放到線程池中運(yùn)行
//第一個(gè)請(qǐng)求任務(wù)過來的時(shí)候mActive是空的
if (mActive == null) {
scheduleNext();
}
}
//具體處理下一個(gè)任務(wù)的方法
protected synchronized void scheduleNext() {
//從隊(duì)列中取一個(gè)任務(wù) 然后執(zhí)行線程池的execute方法
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
//線程池對(duì)象
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
4.關(guān)于mFuture以及具體的線程執(zhí)行和方法調(diào)用
//上文已經(jīng)提到過的繼承自Callable接口的自定義類漓帅,同時(shí)添加了Params數(shù)組參數(shù);
private final WorkerRunnable<Params, Result> mWorker;
//具體的任務(wù)線程對(duì)象
private final FutureTask<Result> mFuture;
//Java庫中的FutureTask聲明及定義,實(shí)現(xiàn)了RunnableFuture接口痴怨,RunnableFuture接口繼承自Runnable,這也是上一步驟的execute要傳入的對(duì)象mFeature的原因忙干,我們主要看run方法。
public class FutureTask<V> implements RunnableFuture<V> {
public void run() {
if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
return;
try {
//此處涉及到了一個(gè)Callable對(duì)象
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//調(diào)用Callable的call方法浪藻。這里就明白為什么我們要看這段代碼了捐迫,就是因?yàn)槲覀円矍宕a執(zhí)行的順序及調(diào)用關(guān)系。
//在執(zhí)行run方法的時(shí)候爱葵,會(huì)回調(diào)call方法施戴,其實(shí)就是我們AsyncTask類中以及上文分析的在構(gòu)造方法中初始化操作的mWorkRunnable匿名內(nèi)部類的call方法,然后執(zhí)行其耗時(shí)操作萌丈。
//當(dāng)執(zhí)行完成時(shí)再調(diào)用done方法赞哗,進(jìn)行結(jié)果分發(fā)。
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
}
上面的兩個(gè)步驟比較關(guān)鍵辆雾,解析完代碼肪笋,重新用文字進(jìn)行梳理一下,具體來說就是:exec.execute(mFuture)執(zhí)行時(shí)乾颁,SerialExecutor將實(shí)現(xiàn)了Runnable以及RunnableFeture接口的mFuture傳遞給實(shí)例對(duì)象執(zhí)行execute方法涂乌。在execute方法中,首先將任務(wù)添加到任務(wù)隊(duì)列中英岭,添加方法為mTasks.offer(Runnable r);然后開始執(zhí)行任務(wù)湾盒,第一次執(zhí)行時(shí)mActive==null,所以直接從任務(wù)隊(duì)列中取一個(gè)任務(wù)并調(diào)用線程池的execute方法诅妹,其實(shí)就是mFuture的run方法罚勾,從任務(wù)隊(duì)列取任務(wù)的方法為mTasks.poll()方法毅人;上一個(gè)任務(wù)執(zhí)行完run方法之后,接著處理下一個(gè)任務(wù)尖殃,依次循環(huán)丈莺;在執(zhí)行mFeture的run方法時(shí),也就是子線程開始執(zhí)行時(shí)送丰,會(huì)回調(diào)call方法缔俄,call方法就是上文的mWorkRunnable中的call,從而call方法中又調(diào)用了doInBackground方法執(zhí)行耗時(shí)操作; doInBackground方法執(zhí)行完畢后器躏,會(huì)調(diào)用postResult方法將結(jié)果分發(fā)回傳俐载。
- 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 InternalHandler sHandler;
//使用了單例模式來保證Handler唯一
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
private static class InternalHandler extends Handler {
public InternalHandler() {
//獲取到UI線程的Looper()
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
//結(jié)果消息分發(fā)
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
//進(jìn)度消息分發(fā)
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
至此,AsyncTask源碼大概的內(nèi)容就是這些登失。歡迎評(píng)論交流遏佣。
掃描下方的二維碼,加入關(guān)注揽浙,所發(fā)布的博客文章會(huì)及時(shí)發(fā)布到公眾號(hào)状婶,方便及時(shí)查看,加入我吧馅巷,一起進(jìn)步膛虫。