AsyncTask 是系統提供一種用來執行異步任務的一個工具類,也是我們一直接觸和使用比較多的一個。
只有我們了解了才能好好的使用它,遇到問題才能馬上明白是可能是哪里引起的。
首先有兩個基礎知識:
第一點 AsyncTask如何做到異步線程與主線程通信
代碼版本:api-20
查看源碼發現,實際上他里面是就 Thread + Handler,是不是瞬間感覺這個也不是一個很神秘的東西了。
//回調主線程
private Result postResult(Result result) {
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
//執行了兩個主線程的方法:一個update和一個Result
private static class InternalHandler extends Handler {
@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;
}
}
}
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
第二點 AsyncTask的線程是如何調度的
這部分是 AsyncTask 內部線程池創建的方式,一共創建了兩個線程池
- SERIAL_EXECUTOR 一個線程的線程池
- SERIAL_EXECUTOR 參見線程池參數
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
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);
//線程池
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
//執行的線程池
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
private static final InternalHandler sHandler = new InternalHandler();
//默認執行的線程池
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
}
}
}
我們閱讀一下源碼會發現在AsyncTask創建對象的時候會創建兩個對象分別是:mWorker和mFuture,這就是前面提到的
Future里面的內容,不明白的需要閱讀一下那篇博客,里面說的很清楚。
然后我們在看一下提交Task地方的代碼:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
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 = params;
exec.execute(mFuture);
return this;
}
這時候我們會發現AsyncTask把我們提交的任務全部都穿起來一個個執行了,不明白可以看一下SerialExecutor的實現方
法。
每次提交的任務,會有下面情況:
- 有執行的就把這個任務添加在一個堆棧里面,等待前面任務執行完再執行后面的
- 沒有任務執行,直接執行當前的任務
所有正常使用AsyncTask來執行一些任務的時候需要特別小心了,不然有個任務執行時間很長后面的任務都沒辦法執行了。
如果不想讓這些人物順序執行可以調用一下這個方法executeOnExecutor,可以指定一個線程池執行。
剩下的就是一些輔助的方法了,例如取消、更新進度等
注:
- 線程池有個等待隊列數量限制的,如果大于這個數量調用會有異常產生,軟件崩潰,當前隊列最大值是:
LinkedBlockingQueue<Runnable>(128),這個各個版本有差異的 - AsyncTask 需要在主線程中創建這個對象,不然Handler的消息也在你創建的那個線程
下面是各個系統下面 AsyncTask 的線程池參數和執行的差異
系統版本 | SERIAL_EXECUTOR/THREAD_POOL_EXECUTOR | 線程池參數 | 等待隊列長度 |
---|---|---|---|
2.2 | THREAD_POOL_EXECUTOR | 5-128-10 | 10 |
2.3 | THREAD_POOL_EXECUTOR | 5-128-1 | 10 |
3.2 | THREAD_POOL_EXECUTOR | 5-128-1 | 10 |
4.0 | SERIAL_EXECUTOR | 5-128-1 | 10 |
4.1 | SERIAL_EXECUTOR | 5-128-1 | 10 |
4.2 | SERIAL_EXECUTOR | 5-128-1 | 10 |
4.3 | SERIAL_EXECUTOR | 5-128-1 | 10 |
4.4 | SERIAL_EXECUTOR | cpu+-cpux2+1-1 | 128 |
5.0 | SERIAL_EXECUTOR | cpu+-cpux2+1-1 | 128 |
6.0 | SERIAL_EXECUTOR | cpu+-cpux2+1-1 | 128 |
N | SERIAL_EXECUTOR | cpu+-cpux2+1-1 | 128 |
謝謝閱讀到這里,覺得好的點個贊吧 _