AsyncTask類結構分析
public abstract class AsyncTask<Params, Progress, Result> {
// 下面幾個都是new線程池的一些參數,就不具體解釋了
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
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);
// 這個線程池是負責管理任務執行的。注意,是static修飾的,整個應用的所有AsyncTask共用
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;
}
// 任務執行中、執行完成,通過handler通知主線程
private static InternalHandler sHandler;
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
// 這個是存儲任務的線程池,也是static修飾的,所有AsyncTask共用這一個線程池存儲任務
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
// 這個是負責執行結果回調的Callback對象(並沒有繼承Runnable)
private final WorkerRunnable<Params, Result> mWorker;
// 這個繼承Runnable,負責把doInBackground()方法中的耗時邏輯集成到Runnable中,才能作爲參數傳給線程池
private final FutureTask<Result> mFuture;
......
......
......
}
這個類裏有兩個線程池,都是static的,全局共享,一個負責存儲Runnable對象,一個負責執行任務,爲了方便後面描述,我們分別命名爲“存儲線程池”和“執行線程池”。
但是線程池只接收Runnable參數,所以需要一個Runnable對象把doInBackground()方法中的代碼集成進去,這樣才能被線程池接收。如何集成?就是在run()方法中調用耗時操作,但是問題又來了,如果把執行結果返回回去呢?
所以又需要WorkerRunnable對象,將耗時操作和執行結果返回封裝一下,在run()方法中調用WorkerRunnable的call()方法。
再看構造方法:
public AsyncTask() {
// 初始化WorkerRunnable對象,封裝耗時操作和執行結果
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
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;
}
};
// 初始化Runnable對象,與WorkerRunnable綁定,線程池中調用Runnable的run()方法時,就會調用WorkerRunnable的call()方法
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);
}
}
};
}
AsyncTask執行流程分析
AsyncTask有兩個重載的execute()方法,一個是默認無參數的,一個是可以自定義Runnable的。先看默認無參數方法:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
// 將存儲線程池作爲參數,調用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()方法。這個方法是我們在實現AsyncTask時可以重寫的方法,最早執行,用於做一些初始化操作,在UI線程中
onPreExecute();
// 將執行參數封裝到WorkerRunnable對象中
mWorker.mParams = params;
// 調用存儲線程池的execute()方法,將FutureTask插入存儲線程池中
exec.execute(mFuture);
return this;
}
再看有參數、可以自定義Runnable的execute()方法:
public static void execute(Runnable runnable) {
// 同樣,將runnabale插入存儲線程池中。跟上面的區別就是,上面插入的Runnable對象是默認的,這裏插入的Runnable對象是自定義的
sDefaultExecutor.execute(runnable);
}
最終都到了存儲線程池sDefaultExecutor的execute()方法,我們看一下SerialExecutor類:
private static class SerialExecutor implements Executor {
// 使用數組隊列存儲Runnable
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
// 當前正在執行的Runnable
Runnable mActive;
public synchronized void execute(final Runnable r) {
// new要給Runnable,將新任務再次封裝一次,插入到隊列尾部
// 由於隊列中的任務需要遵循某種邏輯才能依次執行,所以需要重新封裝一次
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
// 如果當前Runnable爲null,說明這是該應用第一次執行AsyncTask,需要執行scheduleNext()方法啓動“執行線程池”
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
// 取出任務,使用執行線程池來執行任務
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
從上面的run()方法可以看出,如果是第一次,就調用scheduleNext()啓動任務。如果不是第一次,就把新任務插入到存儲線程池中。上一個任務執行完畢後,會調用scheduleNext()方法執行下一個任務。
這裏需要注意的是,從doInBackground()到最終啓動線程執行耗時操作,中間new了3個Runnable對象。
①第一個Runnable,是爲了把doInBackground()中的邏輯代碼封裝到run()方法中,因爲存儲線程池SerialExecutor統一接收Runnable對象作爲參數;
②第二個Runnable,是爲了把耗時操作封裝到固定邏輯的run()方法中,這樣才能達到依次執行的邏輯;
③第三個Runnable,就是執行線程池中的,真正用來執行耗時操作的,這裏會啓動n個核心線程和n個非核心線程。
前兩個Runnable都是爲了代碼的可擴展性和靈活性做的管道封裝,這兩個Runnable都不會調用start()方法啓動,只是調用run()方法執行裏面的代碼而已。
不管怎樣,最終都會調用FutureTask的run()方法:
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
// 這個callable就是前面mFuture = new FutureTask<Result>(mWorker)中的WorkerRunnable
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// 調用WorkerRunnable的call()方法
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);
}
}
在執行線程池中,會在子線程中調用FutureTask的run()方法,而run()方法中又會調用WorkerRunnable的call()方法,所以call()方法是在子線程中調用的:
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//調用doInBackground()方法
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
// 耗時操作執行完畢後通知結果
postResult(result);
}
return result;
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
// 通過Handler通知執行結果,這樣就可以在主線程中得到執行結果了
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
我們在實現doInBackground()方法時,可以在其中調用publishProgress ()方法通知主線程執行進度:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
// 同樣,也是通過Handler通知執行進度的
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
另外,如果我們啓動任務時,調用execute(Runnable runnable)方法,使用自定義的Runnable,那最終就只會調用自定義Runnable的run()方法,系統就無法幫我們回調doInbackGround()、postResult()方法,需要我們自己在run()方法中實現耗時操作的處理、結果返回的處理。