突然發(fā)現(xiàn)自己開發(fā)其實(shí)很少用到AsyncTask?(? ???ω??? ?)在這里補(bǔ)上對它的源碼分析
初見
在Android啟蒙導(dǎo)師黑馬程序員的視頻中曾經(jīng)聽到過一句話虫几,AsyncTask:輕量級的線程工具暂论,方便快捷的實(shí)現(xiàn)工作線程到主線程的通信召烂。
在翻看AsyncTask源碼時(shí)一部分注釋如下
/**
* <p>AsyncTask enables proper and easy use of the UI thread. This class allows you
* to perform background operations and publish results on the UI thread without
* having to manipulate threads and/or handlers.</p>
*
* <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
* and does not constitute a generic threading framework. AsyncTasks should ideally be
* used for short operations (a few seconds at the most.)
大意呢就是AsyncTask可以允許你在工作線程中發(fā)布結(jié)果到UI線程咽弦,但是它適合短時(shí)間操作最多幾秒鐘,嗨喲,這么傲嬌,走了走了绍申,還是滾去用RxJava算了,HandlerThread也行顾彰。
AsyncTask:別看注釋嚇人极阅,我這樣都沒被淘汰,親兒子啊~~
那我們再留下看看他還有什么話要說(;?_?)
使用
可以看到AsyncTask需要傳入3個(gè)泛型參數(shù)
public abstract class AsyncTask<Params, Progress, Result>
依次代表傳入工作線程的參數(shù)涨享,進(jìn)度回調(diào)筋搏,回調(diào)給UI線程的結(jié)果,艾瑪厕隧,都有進(jìn)度回調(diào)奔脐,這么一看好像很NB的樣子。
我們隨便寫個(gè)AsyncTask看看
TestTask task = new TestTask();
task.execute(1, 2, 3, 4, 5, 6);
/**
* 測試
*/
class TestTask extends AsyncTask<Integer, Integer, String> {
private static final String TAG = "TestTask";
@Override
protected void onPreExecute() {
//預(yù)處理(UI線程)
}
@Override
protected String doInBackground(Integer... params) {
//必須實(shí)現(xiàn)吁讨,異步耗時(shí)任務(wù)(工作線程)
StringBuilder sb = new StringBuilder();
for (int i : params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
sb.append(i);
}
Log.d(TAG, "doInBackground: " + sb.toString());
return sb.toString();
}
@Override
protected void onProgressUpdate(Integer... values) {
//進(jìn)度回調(diào)(UI線程)
Log.d(TAG, "onProgressUpdate: " + values[0]);
}
@Override
protected void onPostExecute(String s) {
//回調(diào)給UI線程(UI線程)
Log.d(TAG, "onPostExecute: " + s);
}
}
過了一會果然輸出了2行日志髓迎,進(jìn)度什么的還是要自己來搞
doInBackground: 123456
onPostExecute: 123456
分析
那么我們來看看execute
這個(gè)方法是在怎么啟動的
//UI線程限定
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@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;
}
看到這里,我們有了大概的思路建丧,execute
方法內(nèi)部調(diào)用了默認(rèn)的執(zhí)行方法來執(zhí)行排龄,相對狀態(tài)進(jìn)行校驗(yàn)過后,將參數(shù)賦值后翎朱,執(zhí)行方法涣雕,我們接下來先看看參數(shù)是在怎么賦值的艰亮,
mWorker.mParams = params;
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
可以發(fā)現(xiàn)mWorker其實(shí)就就是簡簡單單一個(gè)實(shí)現(xiàn)Callback接口的靜態(tài)內(nèi)部類,里面存放參數(shù)挣郭,那么exec.execute(mFuture);
呢迄埃,execute
傳遞進(jìn)去了一個(gè)默認(rèn)的執(zhí)行規(guī)則
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
//execute 默認(rèn)
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
其中Executor
是一個(gè)接口
public interface Executor {
void execute(Runnable command);
}
SerialExecutor,翻譯出來叫做串行執(zhí)行兑障,我們來瞧瞧TA的實(shí)現(xiàn)
private static class SerialExecutor implements Executor {
//雙端隊(duì)列侄非,可以簡單的理解成一個(gè)隊(duì)列
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
//正在運(yùn)行中的
Runnable mActive;
public synchronized void execute(final Runnable r) {
//將一個(gè)runnable放置到隊(duì)列末尾
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
//不考慮執(zhí)行結(jié)果如何都會執(zhí)行下一個(gè)任務(wù)
scheduleNext();
}
}
});
if (mActive == null) {
//第一次從這里開始執(zhí)行任務(wù)
scheduleNext();
}
}
protected synchronized void scheduleNext() {
//從隊(duì)列取出一個(gè)任務(wù)
if ((mActive = mTasks.poll()) != null) {
//真正開始執(zhí)行
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
看到這里,敢情SerialExecutor
就是THREAD_POOL_EXECUTOR
的封裝版流译,保證里面的runnable都是串行執(zhí)行逞怨,名至實(shí)歸,看到這里福澡,筆者突然發(fā)現(xiàn)小小的AsyncTask中蘊(yùn)含了不少的東西叠赦,那么我們完整的看下AsyncTask的構(gòu)造器和成員變量
深入
//API25
public abstract class AsyncTask<Params, Progress, Result> {
//手機(jī)CPU數(shù)目
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//根據(jù)CPU來配置核心線程數(shù)目,每個(gè)編譯版本可能不一樣
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//線程池最大的容納數(shù)量
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//空線程30s备镌遥活
private static final int KEEP_ALIVE_SECONDS = 30;
//配置線程池時(shí)除秀,給每個(gè)線程名字命名
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());
}
};
//阻塞隊(duì)列,限長128
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
//線程池的執(zhí)行
public static final Executor THREAD_POOL_EXECUTOR;
//靜態(tài)代碼塊算利,全局都是這個(gè)線程池
static {
//將上述的參數(shù)作為構(gòu)造參數(shù)傳入
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
//消息的what
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//回調(diào)的Handler
private static InternalHandler sHandler;
//實(shí)現(xiàn)Callback册踩,存放參數(shù)
private final WorkerRunnable<Params, Result> mWorker;
//執(zhí)行的具體方法
private final FutureTask<Result> mFuture;
//記錄狀態(tài)
private volatile Status mStatus = Status.PENDING;
//高比發(fā)下保證原子性操作,記錄任務(wù)是否取消效拭,是否執(zhí)行
private final AtomicBoolean mCancelled = new AtomicBoolean();
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
private static class SerialExecutor implements Executor {
//上文已有暂吉,省略。缎患。慕的。
}
public enum Status {
//等待執(zhí)行
PENDING,
//執(zhí)行中
RUNNING,
//結(jié)束
FINISHED,
}
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//任務(wù)執(zhí)行
mTaskInvoked.set(true);
Result result = null;
try {
//設(shè)置線程的優(yōu)先級
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//執(zhí)行方法
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
//結(jié)果post
postResult(result);
}
return result;
}
};
//相當(dāng)于修飾者模式
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
//異常的情況下,將結(jié)果返回挤渔,一般執(zhí)行不進(jìn)去
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);
}
}
};
}
每處地方筆者幾乎都打上了注釋业稼,畢竟我就是那么的貼心,恩(°?°)?蚂蕴,其中有幾處細(xì)節(jié)
AsyncTask的線程池配置根據(jù)手機(jī)配置來的低散,緩沖隊(duì)列默認(rèn)是128,也就是說如果有一只4核的手機(jī)骡楼,那么根據(jù)如上API25的配置
- CPU_COUNT=4
- CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)) = 4
- MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1 = 7
線程池中最大容納7個(gè)線程熔号,同時(shí)處理4個(gè)工作線程,滿出來的放到BlockingQueue
中鸟整,也就是128的數(shù)量限制引镊,默認(rèn)還是串行執(zhí)行,如果工作線程過于密集,不僅會阻塞后續(xù)的線程弟头,還有可能拋出RejectedExecutionException
異常吩抓,被線程池拒絕,至此赴恨,前文的AsyncTask的注釋提示適合短時(shí)間的任務(wù)也就揭開了面紗疹娶。
當(dāng)后臺任務(wù)完成會調(diào)用這個(gè)方法返回結(jié)果
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
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;
}
}
}
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
通過InternalHandler
來分發(fā)消息,然后對應(yīng)執(zhí)行mTask的相關(guān)回調(diào)方法
總結(jié)
綜上所訴伦连,AsyncTask驅(qū)動的其實(shí)是mFuture
雨饺,本質(zhì)也是一個(gè)Runnable;進(jìn)度回調(diào)由我們自己調(diào)用publishProgress
惑淳,工作線程限定
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
一遍源碼看下來额港,AsyncTask其實(shí)是將一個(gè)異步任務(wù)分配到線程池中來執(zhí)行,完成后通過Handler來分發(fā)的一個(gè)封裝的庫歧焦,由于默認(rèn)的執(zhí)行還是串行的移斩,雖然支持多線程并行,但是不太適合高頻的網(wǎng)絡(luò)請求绢馍,適用于一些輕量的IO操作向瓷。
Ps:由于使用過程中帶有一些坑,就偷懶不放調(diào)用流程圖了
參考:
AsyncTask和AsyncTaskCompat源碼解析
Android AsyncTask 源碼解析
凡勞苦擔(dān)重?fù)?dān)的人可以到我這里來痕貌,我就使你們得安息风罩。 (馬太福音 11:28 和合本)