使用
AsyncTask的使用不是本文的重點(diǎn),我相信讀者也不是來(lái)了解這個(gè)的,所以就先簡(jiǎn)單的介紹下它的使用,幫助大家回憶。
AsyncTask的實(shí)現(xiàn):
public class DownloadTask extends AsyncTask<Object, Integer, Boolean> {
/**
* 在執(zhí)行任務(wù)之前調(diào)用,運(yùn)行在主線程,可用來(lái)做布局更新等
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* 執(zhí)行后臺(tái)任務(wù),運(yùn)行在子線程
*/
@Override
protected Boolean doInBackground(Object... objects) {
return false;
}
/**
* 更新進(jìn)度,運(yùn)行在主線程,在doInBackground方法中調(diào)用publishProgress(Integer... values)會(huì)自動(dòng)調(diào)用該方法
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
/**
* 后臺(tái)任務(wù)結(jié)束后調(diào)用,運(yùn)行在主線程,參數(shù)aBoolean是doInBackground()方法的返回值
*/
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
}
/**
* 主動(dòng)調(diào)用cancel()方法,或者doInBackground()方法拋出異常
*/
@Override
protected void onCancelled() {
super.onCancelled();
}
}
調(diào)用:
DownloadTask downloadTask = new DownloadTask();
downloadTask.execute(object1, object2);
//這里的參數(shù)object1, object2最終會(huì)傳給doInBackground(Object... objects);
源碼思路
先說(shuō)下整體的實(shí)現(xiàn)思路:創(chuàng)建線程池執(zhí)行耗時(shí)任務(wù),通過(guò)handler將進(jìn)度、結(jié)果等送回主線程。
細(xì)節(jié)方面,我們需要研究下,該線程池是怎樣的線程池,它的執(zhí)行邏輯是怎樣的:核心線程數(shù),最大線程數(shù),等待隊(duì)列,拒絕策略等細(xì)節(jié)。順便再了解下上面代碼中的onPreExecute(),onProgressUpdate()等生命周期是在什么時(shí)候執(zhí)行的。
開(kāi)始研究
我們就從我們使用的地方開(kāi)始下手:
DownloadTask downloadTask = new DownloadTask();
downloadTask.execute(object1, object2);
1.下面是其構(gòu)造方法:
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 {
//設(shè)置標(biāo)志,表示工作任務(wù)開(kāi)始執(zhí)行
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);
}
}
};
}
結(jié)構(gòu)很簡(jiǎn)單,一共初始化了三個(gè)全局變量mHandler,mWorker,mFuture。
mHandler,從上面的代碼看,是創(chuàng)建了一個(gè)綁定callbackLooper的handler,所以講道理如果callbackLooper是另一個(gè)子線程的Looper對(duì)象,它也可是實(shí)現(xiàn)兩個(gè)子線程之間的數(shù)據(jù)交互。但是,由于該構(gòu)造方法被@hide隱藏了,我們使用的默認(rèn)無(wú)參構(gòu)造器,最終會(huì)使callbackLooper為null,也就是說(shuō)mHandler賦值為getMainHandler()綁定了主線程。
下面是該handler實(shí)現(xiàn)的handleMessage方法,一個(gè)是處理結(jié)果,一個(gè)是處理進(jìn)度的,這里就先不展開(kāi)細(xì)說(shuō)了,后邊分析到工作線程執(zhí)行到各個(gè)階段時(shí)再細(xì)說(shuō)。
@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;
}
}
mWorker,WorkerRunnable是抽象類(lèi),implements自Callable接口,對(duì)線程池框架比較熟悉的可以知道它將在子線程中調(diào)用執(zhí)行,了解到這點(diǎn)就夠了。
在mWorker實(shí)現(xiàn)的call()方法中最主要的一行代碼doInBackground(mParams);它在這里執(zhí)行了我們的工作任務(wù),然后在catch異常的時(shí)候設(shè)置了標(biāo)志位:mCancelled.set(true),最終在finally中執(zhí)行了postResult()方法。postResult()的邏輯:
private Result postResult(Result result) {
//getHandler()會(huì)返回mHandler,也就是上面介紹的綁定了主線程Looper對(duì)象的Handler
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
這就和我們上面講到的handleMessage對(duì)Message的處理聯(lián)系了起來(lái),最終會(huì)執(zhí)行finish()方法,并在這里調(diào)用我們實(shí)現(xiàn)的onCancelled()或者onPostExecute()生命周期:
private void finish(Result result) {
//isCancelled()方法會(huì)判斷是否是取消導(dǎo)致,
//比如上面說(shuō)的執(zhí)行mWorker.call()時(shí)catch異常和我們做活動(dòng)調(diào)用AsyncTask的cancel()方法會(huì)使isCancelled()返回ture
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
WorkerRunnable除了implements Callable接口還添加了個(gè)mParams數(shù)組,也就是doInBackground(mParams),執(zhí)行時(shí)會(huì)傳入的參數(shù)
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
mFuture FutureTask本篇不做深入的了解,它的目的是獲取子線程運(yùn)算結(jié)果和提供子線程的中斷方法。上面代碼對(duì)于mFuture的初始化可以看到它將mWorker封裝在了內(nèi)部,所以以后的操作對(duì)象都變?yōu)榱薽Future。mWork只是提供了call()方法(Callable接口)和參數(shù)mParams。
2.execute:
構(gòu)造方法就是初始化了三個(gè)變量,mHandler,mWorker,mFuture。接下來(lái)我們看下execute()執(zhí)行了哪些步奏:downloadTask.execute(object1, object2);
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
//內(nèi)部調(diào)用了executeOnExecutor方法
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變量賦值
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
可以看到execute()就是調(diào)用了executeOnExecutor()方法。executeOnExecutor()的前部分就是判斷了當(dāng)前AsyncTask的狀態(tài)只有在Status.PENDING的狀態(tài)才可以正常運(yùn)行,并且在運(yùn)行后立即將狀態(tài)改為了Status.RUNNING,也就是說(shuō)同一個(gè)AsyncTask對(duì)象只能execute()一次。
接著就是調(diào)用了onPreExecute();也就是我們執(zhí)行任務(wù)前在主線程做一些初始化的操作,比如加載界面。
最后最重要的工作exec.execute(mFuture)來(lái)執(zhí)行我們的工作任務(wù)。毋庸置疑,該方法最終會(huì)執(zhí)行到mWorker的call()方法。我們現(xiàn)在要研究的就是這個(gè)Executor對(duì)象(即調(diào)用executeOnExecutor()時(shí)傳入的sDefaultExecutor),它是怎樣的線程池,我們傳入的FutureTask對(duì)象將被如何調(diào)用。
sDefaultExecutor
終于我們要開(kāi)始研究AsyncTask的核心內(nèi)容了sDefaultExecutor(其實(shí)不是)。為什么說(shuō)不是呢,因?yàn)閟DefaultExecutor只是一個(gè)任務(wù)安排者,并不真正的創(chuàng)建線程執(zhí)行任務(wù)??聪聅DefaultExecutor的源碼:
/**
*sDefaultExecutor最終會(huì)指向SerialExecutor對(duì)象
**/
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
//SerialExecutor并沒(méi)有任何地方創(chuàng)建線程,execute也只是將任務(wù)放進(jìn)ArrayDeque隊(duì)列中
//之前我們傳入的是FutureTask對(duì)象,而這里需要的參數(shù)是Runnable對(duì)象是因?yàn)椋?
//FutureTask也實(shí)現(xiàn)了Runnable接口,并將Callable接口(即mWorker)的call()方法在run()方法中調(diào)用
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才是最終執(zhí)行任務(wù)的線程池
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
ok,我們先看下它是怎樣安排任務(wù)的。1.將任務(wù)runnable稍作包裝提交到mTasks中并插入到隊(duì)列尾部。2.判斷mActive是否為null,如果不為null則執(zhí)行scheduleNext()。
第一次運(yùn)行AsyncTask時(shí)肯定為null,所以會(huì)立即執(zhí)行scheduleNext(),可以看到mTasks.poll()會(huì)從隊(duì)列首部取出任務(wù)賦值給mActive,并且通過(guò)真正的線程池THREAD_POOL_EXECUTOR去執(zhí)行。
當(dāng)任務(wù)完成后會(huì)在finally中調(diào)用scheduleNext()方法去查看mTasks隊(duì)列中是否有剩余任務(wù),如果有則安排,沒(méi)有則mActive置為null。保證下次創(chuàng)建新的AsyncTask時(shí),mActive為正確值(因?yàn)閟DefaultExecutor為static變量,全局只有一個(gè)sDefaultExecutor對(duì)象),這也表示如果短時(shí)間內(nèi)創(chuàng)建多個(gè)AsyncTask,并且每個(gè)AsyncTask執(zhí)行時(shí)間還比較長(zhǎng),那后執(zhí)行AsyncTask.execute()方法的任務(wù)將需要等待前面的任務(wù)執(zhí)行完成才能開(kāi)始。也就是說(shuō)AsyncTask其實(shí)是串行執(zhí)行的。
若想并行執(zhí)行也是有方法的,直接調(diào)用executeOnExecutor(THREAD_POOL_EXECUTOR, params);跳過(guò)sDefaultExecutor的代理。
THREAD_POOL_EXECUTOR
終于到了研究線程池的這一步了
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), sThreadFactory);
threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
核心線程數(shù):CORE_POOL_SIZE = 1,最大線程數(shù):MAXIMUM_POOL_SIZE = 20,空閑線程持續(xù)時(shí)間KEEP_ALIVE_SECONDS = 3(秒),SynchronousQueue這是等待隊(duì)列,線程工廠: sThreadFactory,最后設(shè)置了拒絕策略sRunOnSerialPolicy。
SynchronousQueue沒(méi)有容量,是無(wú)緩沖等待隊(duì)列,是一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列。也就是說(shuō)最多同時(shí)執(zhí)行20個(gè)線程任務(wù)。再有新的任務(wù)則會(huì)執(zhí)行拒絕策略sRunOnSerialPolicy,我們看下sRunOnSerialPolicy的源碼:
private static final int BACKUP_POOL_SIZE = 5;
private static final RejectedExecutionHandler sRunOnSerialPolicy =
new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
android.util.Log.w(LOG_TAG, "Exceeded ThreadPoolExecutor pool size");
// As a last ditch fallback, run it on an executor with an unbounded queue.
// Create this executor lazily, hopefully almost never.
synchronized (this) {
if (sBackupExecutor == null) {
sBackupExecutorQueue = new LinkedBlockingQueue<Runnable>();
sBackupExecutor = new ThreadPoolExecutor(
BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,
TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory);
sBackupExecutor.allowCoreThreadTimeOut(true);
}
}
sBackupExecutor.execute(r);
}
};
很簡(jiǎn)單,又創(chuàng)建了個(gè)備用線程池,只有BACKUP_POOL_SIZE個(gè)核心線程(5個(gè)),然后核心線程也會(huì)超時(shí),畢竟備用線程池,邏輯上來(lái)講需要也不需要長(zhǎng)時(shí)間保留。sBackupExecutorQueue的容量是Integer.Max,所以說(shuō)若短時(shí)間執(zhí)行大量任務(wù),則會(huì)將后續(xù)的任務(wù)都添加在sBackupExecutorQueue中,然后等待備用線程的調(diào)用,這時(shí)候,主線程池的即使結(jié)束了任務(wù),也不會(huì)去執(zhí)行新的任務(wù),sBackupExecutorQueue中的任務(wù)將由備用線程池的5個(gè)線程去執(zhí)行。這點(diǎn)上沒(méi)有注意到可能會(huì)影響AsyncTask的使用效率:

總結(jié):
整體來(lái)說(shuō)AsyncTask思路很簡(jiǎn)單,就是創(chuàng)建線程池,在子線程執(zhí)行任務(wù)前調(diào)用onPreExecute(),在子線程中調(diào)用doInBackground(),然后執(zhí)行過(guò)程中調(diào)用publishProgress()通過(guò)handler發(fā)送進(jìn)度到主線程執(zhí)行onProgressUpdate(),最后執(zhí)行完成后再通過(guò)handler發(fā)送Result到主線程執(zhí)行onPostExecute()或者onCancelled()
需要多注意的就是對(duì)于線程池要有一定的了解,否則讀起源碼來(lái)將有些困難。