AsyncTask源碼分析(Android7.0)
1.Android 3.0版本之前的AsyncTask
下面是Android 2.3.7版本的AsyncTask的部分源碼。
public abstract class AsyncTask<Params, Progress, Result> {
private static final String LOG_TAG = "AsyncTask";
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
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 ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
...
}</code></pre>
在這里又看到了ThreadPoolExecutor,它的核心線程數是5個,線程池允許創建的最大線程數為128,非核心線程空閑等待新任務的最長時間為10秒。采用的阻塞隊列是LinkedBlockingQueue,它的容量為10。3.0版本之前的AsyncTask有一個缺點就是,線程池最大的線程數為128,加上阻塞隊列的10個任務,所以AsyncTask最多能同時容納138個任務,當提交第139任務時就會執行飽和策略,默認拋出RejectedExecutionException異常。
2.Android 7.0版本的AsyncTask
在這里采用Android 7.0版本的AsyncTask作為例子,首先來看AsyncTask的構造函數:
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {//1
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
mFuture = new FutureTask<Result>(mWorker) {//2
@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);
}
}
};
}</code></pre>
從注釋1處看這個WorkerRunnable實現了Callable<Result>接口,并實現了它的call方法,在call方法中調用了doInBackground(mParams)來處理任務并得到結果,并最終調用postResult將結果投遞出去。注釋2處的FutureTask是一個可管理的異步任務,它實現了Runnable和Futrue這兩個接口。因此它可以包裝Runnable和Callable<V>,并提供給Executor執行。也可以調用線程直接執行(FutureTask.run())。在這里WorkerRunnable作為參數傳遞給了FutureTask。這兩個變量會暫時保存在內存中,稍后會用到它們。
當要執行AsyncTask時,需要調用它的execute方法,代碼如下所示。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
execute方法又調用了executeOnExecutor方法:
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;//1
exec.execute(mFuture);
return this;
}</code></pre>
這里會首先調用 onPreExecute方法,在注釋1處將AsyncTask的參數傳給WorkerRunnable,從前面我們知道WorkerRunnable會作為參數傳遞給了FutureTask,因此,參數被封裝到FutureTask中。接下來會調用exec的execute方法,并將mFuture也就是前面講到的FutureTask傳進去。這里exec是傳進來的參數sDefaultExecutor,它是一個串行的線程池,它的代碼如下所示。
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() {//1
public void run() {
try {
r.run();//2
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
從注釋1處可以看出,當調用SerialExecutor 的execute方法時,會將FutureTask加入到mTasks中。當任務執行完或者當前沒有活動的任務時都會執行scheduleNext方法,它會從mTasks取出FutureTask任務并交由THREAD_POOL_EXECUTOR處理。關于THREAD_POOL_EXECUTOR,后面會介紹。從這里看出SerialExecutor是串行執行的。在注釋2處可以看到執行了FutureTask的run方法,它最終會調用WorkerRunnable的call方法。
前面我們提到call方法postResult方法將結果投遞出去,postResult方法代碼如下所示。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
在postResult方法中會創建Message,并將結果賦值給這個Message,通過getHandler方法得到Handler,并通過這個Handler發送消息,getHandler方法如下所示。
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
在getHandler方法中創建了InternalHandler,InternalHandler的定義如下所示。
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@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;
}
}
}
在接收到MESSAGE_POST_RESULT消息后會調用AsyncTask的finish方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果AsyncTask任務被取消了則執行onCancelled方法,否則就調用onPostExecute方法。而正是通過onPostExecute方法我們才能夠得到異步任務執行后的結果。
接著回頭來看SerialExecutor ,線程池SerialExecutor主要用來處理排隊,將任務串行處理。 SerialExecutor中調用scheduleNext方法時,將任務交給THREAD_POOL_EXECUTOR。THREAD_POOL_EXECUTOR同樣是一個線程池,用來執行任務。
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
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 BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
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;
}
THREAD_POOL_EXECUTOR指的就是threadPoolExecutor,他的核心線程和線程池允許創建的最大線程數都是由CPU的核數來計算出來的。它采用的阻塞隊列仍舊是LinkedBlockingQueue,容量為128。
到此, Android 7.0版本的AsyncTask的源碼就分析完了,在AsyncTask中用到了線程池,線程池中運行線程并且又用到了阻塞隊列,因此,本章前面介紹的知識在這一節中做了很好的鋪墊。Android 3.0及以上版本用SerialExecutor作為默認的線程,它將任務串行的處理保證一個時間段只有一個任務執行,而3.0之前版本是并行處理的。關于3.0之前版本的缺點在3.0之后版本也不會出現,因為線程是一個接一個執行的,不會出現超過任務數而執行飽和策略。如果想要在3.0及以上版本使用并行的線程處理可以使用如下的代碼:
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
其中asyncTask是我們自定義的AsyncTask,當然也可以傳入Java提供的線程池,比如傳入CachedThreadPool。
asyncTask.executeOnExecutor(Executors.newCachedThreadPool(),"");
也可以傳入自定義的線程池:
Executor exec =new ThreadPoolExecutor(0, Integer.MAX_VALUE,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
asyncTask.executeOnExecutor(exec,"");
來自:http://www.jianshu.com/p/ed7d9fb724cf