1、AsyncTask源碼分析
1、構造方法
先看構造方法,在類初始化的時候,創(chuàng)建了Callable對象和FutureTask對象,并用FutureTask對象來包裝Callable對象,call()方法將做為線程的執(zhí)行體。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//當前任務已被調用過
mTaskInvoked.set(true);
try {
...
result = doInBackground(mParams);
} catch (Throwable tr) {
...
} finally {
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {...};
}
但是為什么要使用FutureTask和Callable,直接使用Runnable不可以嗎?
2、InternalHandler
postResult()方法會通過InternalHandler,向主線程發(fā)送一個MESSAGE_POST_RESULT消息;InternalHandler收到消息后,會調用AsyncTask的finish()方法,然后就可以將結果傳遞給onPostExecute()方法了。
private Result postResult(Result result) {
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
InternalHandler,用于將執(zhí)行環(huán)境從線程池,切換到主線程
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@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;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
從以上代碼中我們可以看到,sHandler是一個靜態(tài)的Handler對象。我們知道創(chuàng)建Handler對象時需要當前線程的Looper,所以我們?yōu)榱艘院竽軌蛲ㄟ^sHandler將執(zhí)行環(huán)境從后臺線程切換到主線程(即在主線程中執(zhí)行handleMessage方法),我們必須使用主線程的Looper,因此必須在主線程中創(chuàng)建sHandler。這也就解釋了為什么必須在主線程中加載AsyncTask類,是為了完成sHandler這個靜態(tài)成員的初始化工作。
3、execute()方法
execute()方法接收的參數是Params類型的參數,這個參數會一路傳遞到doInBackground方法中;通過execute()方法,可以將FutureTask對象添加到線程池(SerialExecutor)中
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
如下,當AsyncTask對象的當前狀態(tài)為RUNNING或FINISHED時,調用execute方法會拋出異常,這意味著不能對正在執(zhí)行任務的AsyncTask對象或是已經執(zhí)行完任務的AsyncTask對象調用execute方法,這就是‘一個AsyncTask對象只能調用一次execute方法’的原因
@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;
}
AsyncTask有兩個線程池:sDefaultExecutor (SerialExecutor)、THREAD_POOL_EXECUTOR。
sDefaultExecutor,是一個串行的線程池,主要是把任務加到任務緩存隊列中;THREAD_POOL_EXECUTOR用于真正的執(zhí)行任務
- mTask代表這個線程池的任務緩存隊列,我們可以使用offer()方法向這個隊列添加任務。
- mActive代表當前正在執(zhí)行的任務,可以通過mTasks.poll()取出一個任務,使用THREAD_POOL_EXECUTOR.execute(mActive);執(zhí)行這個任務,這時后臺任務便開始你真正執(zhí)行了。
THREAD_POOL_EXECUTOR線程池,會執(zhí)行mTasks中的run()方法——>mFuture的run()方法——>Callable的call()方法——>doInBackground()方法
private static volatile Executor sDefaultExecutor = new SerialExecutor();
private static class SerialExecutor implements Executor {
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);
}
}
}
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
2、AsyncTask的簡單使用
AsyncTask asyncTask=new AsyncTask<String, Integer, Void>() {
@Override
protected void onPreExecute() {}
@Override
protected void onPostExecute(Void aVoid) { }
@Override
protected void onProgressUpdate(Integer... values) {}
@Override
protected Void doInBackground(String... params) { return null;}}
.execute("");
- onPreExecute():在主線程中進行,在異步任務開始之前調用
- doInBackground()在線程池中執(zhí)行,用于執(zhí)行異步任務
- onProgressUpdate():在主線程中進行,在異步任務執(zhí)行進度發(fā)生變化時調用
- **onPostExecute() **:在主線程中進行,在異步任務執(zhí)行完調用
3、 AsyncTask的局限性
AsyncTask的優(yōu)點在于執(zhí)行完后臺任務后可以很方便的更新UI,然而使用它存在著諸多的限制
在Android 4.1版本之前,AsyncTask類必須在主線程中加載,這意味著對AsyncTask類的第一次訪問必須發(fā)生在主線程中;在Android 4.1以及以上版本則不存在這一限制,因為ActivityThread(代表了主線程)的main方法中會自動加載AsyncTask
AsyncTask對象要在主線程中創(chuàng)建
execute()方法要在主線程調用
一個AsyncTask對象對象只能執(zhí)行一次execute()方法
內存泄漏:如果AsyncTask被聲明為Activity的非靜態(tài)的內部類,那么AsyncTask會保留一個對創(chuàng)建了AsyncTask的Activity的引用。如果Activity已經被銷毀,AsyncTask的后臺線程還在執(zhí)行,它將繼續(xù)在內存里保留這個引用,導致Activity無法被回收,引起內存泄露。
</br></br>
參考:Android開發(fā)藝術探討、深入理解AsyncTask的工作原理
</br></br>