流程解讀
- 自定義的繼承類:因為AsyncTask為抽象類形纺,無法直接創(chuàng)建肃廓,必須繼承它實現(xiàn)一個子類般妙。
a. 常見的方法
onPreExecute():在執(zhí)行任務(wù)前調(diào)用阻逮,位于UI線程內(nèi)
doInBackground():執(zhí)行任務(wù)過程,位于非UI線程內(nèi)
publishProgress():發(fā)布任務(wù)進度娩梨,一般在doInBackground()中調(diào)用沿腰,將數(shù)據(jù)傳遞給調(diào)onPregressUpdate()方法
onPregressUpdate():更新進度條,位于UI線程
onPostExecute():doInBackgound()方法完成后調(diào)用狈定,位于UI線程
onCancelled():取消任務(wù)颂龙,位于UI線程
b. 定義類型
class MyTask extends AsyncTask<Params, Progress, Result>
Params為傳入的數(shù)據(jù),比如url纽什;因此措嵌,通常設(shè)置為String類型;
Progress為更新的進度芦缰,通常為Integer類型;
Result為返回的結(jié)果企巢,如果我們希望返回一個文件,那么其對應(yīng)類型為File让蕾;
- 創(chuàng)建自定義的MyTask類
MyTask task = new MyTask(...);
創(chuàng)建該類浪规,實際上就會調(diào)用AsyncTask的構(gòu)造函數(shù),如下:
//創(chuàng)建一個異步任務(wù)探孝,注意這里必須在UI線程中創(chuàng)建
public AsyncTask(){
//定義任務(wù)執(zhí)行過程笋婿,注意這里還沒開始執(zhí)行任務(wù),只是定義任務(wù)的執(zhí)行過程
mWorker = new WorkerRunnable<Params, Result>() {
@Override
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//交給子類去實現(xiàn)再姑,獲取到結(jié)果
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr){
mCancelled.set(true);
throw tr;
} finally {
//最后提交結(jié)果
postResult(result);
}
return result;
}
};
//實際上萌抵,這里用FutureTask包裝Callable的目的是為之后提交給線程池執(zhí)行,因為線程池并不接收Callable類型
mFuture = new FutureTask<Result>(mWorker){
@Override
protected void done() {
try {
//若任務(wù)并沒有執(zhí)行過元镀,則需要調(diào)用get()方法獲取到結(jié)果绍填,然后再提交結(jié)果
postResultIfNotInvoked(get());
} catch (InterruptedException e){
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e){
throw new RuntimeException("An error occurred while executing doInBackgound", e.getCause());
} catch (CancellationException e){
postResultIfNotInvoked(null);
}
}
};
}
在AsyncTask構(gòu)造函數(shù)內(nèi),初始化了兩個mWorker
和mFuture
兩個變量栖疑。我們?nèi)菀卓吹狡渲衜Futrue實際上就是一個包裝mWorker的FutrueTask實例讨永。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result>{
Params[] mParams;
}
如上,實際上WorkerRunnable類型即為Callable類型遇革。
- 執(zhí)行MyTask實例
mTask.execute(url);
其對應(yīng)調(diào)用AsyncTask中的execute方法卿闹,如下:
//外部調(diào)用方法,執(zhí)行任務(wù)
public final AsyncTask<Params, Progress, Result> execute(Params... params){
return executeOnExecutor(sDefaultExecutor, params);
}
//真正執(zhí)行任務(wù)的地方
private 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 benn executed.");
}
}
//標(biāo)識為正在執(zhí)行
mStatus = Status.RUNNING;
//執(zhí)行前調(diào)用
onPreExecute();
mWorker.mParams = params;
//執(zhí)行任務(wù)B芸臁6亡!揪漩!
exec.execute(mFuture);
return this;
}
首先我們看到executeOnExecutor
中的onPreExecute()
方法旋恼,這是任務(wù)前執(zhí)行的方法,然后執(zhí)行exec.execute(mFuture)
奄容,我們回到mFuture的定義冰更,我們知道m(xù)Future只是mWorker的一層包裝产徊,目的是為了交給線程池執(zhí)行。而mWorkder中會執(zhí)行result = doInBackground(mParams);
蜀细,這個是交給子類去實現(xiàn)舟铜,獲取到結(jié)果。最后再分發(fā)結(jié)果postResult(result);
奠衔。
//獲取到Handler對象
private static Handler getHandler(){
synchronized (AsyncTask.class){
if (sHandler == null){
sHandler = new InternalHandler();
}
return sHandler;
}
}
//提交結(jié)果
private Result postResult(Result result){
//創(chuàng)建消息
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
//發(fā)送消息
message.sendToTarget();
return result;
}
我們可以看到消息將對應(yīng)的結(jié)果通過一個InternalHandler類型來發(fā)送
//定義一個UI線程上的Handler對象
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:
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
如上谆刨,該類型為UI線程上的一個Handler對象,保證發(fā)送的消息可以在UI線程中接收涣觉,我們先看到其MESSAGE_POST_RESULT
類型痴荐,調(diào)用result.mTask.finish(result.mData[0]);
方法
//任務(wù)執(zhí)行完畢,提交結(jié)果官册,并標(biāo)識
private void finish(Result result){
if (isCancelled()){
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
我們可以看到在finish方法中生兆,調(diào)用了onPostExecute(result)
方法將結(jié)果發(fā)送出去。這樣一個完整的流程就結(jié)束了膝宁。
當(dāng)然鸦难,還有其更新進度方面,我們回到publishProgress()
方法
//更新進度员淫,并發(fā)送進度消息
protected final void publishProgress(Progress... values){
if (!isCancelled()){
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
回到InternalHandler
中合蔽,我們可以看到其對應(yīng)的消息類型,會調(diào)用onProgressUpdate()
方法
細節(jié)解析
- AsyncTask默認是使用串行執(zhí)行的方式
//線程執(zhí)行器介返,默認為串行執(zhí)行
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
如何實現(xiàn)串行執(zhí)行拴事?
添加任務(wù)時,將下一個任務(wù)添加到上一個任務(wù)完成后執(zhí)行
//實現(xiàn)串行執(zhí)行
private static class SerialExecutor implements Executor{
//雙向隊列圣蝎,存儲任務(wù)
final ArrayDeque<Runnable> mTasks = new ArrayDeque<>();
//當(dāng)前正在執(zhí)行的任務(wù)
Runnable mActive;
@Override
public void execute(final Runnable r) {
//添加到隊尾
//注意:a. 在這里不是直接傳入r刃宵,而是重新定義一個runnable,目的在于當(dāng)前任務(wù)執(zhí)行完后徘公,再從任務(wù)隊列中獲取到下一個牲证,以保證串行
// b. 在這里只是重新定義runnable,并沒有開始真正執(zhí)行!9孛妗坦袍!
mTasks.offer(new Runnable() {
@Override
public void run() {
try {
r.run();
} finally {
//獲取到下一個任務(wù)
scheduleNext();
}
}
});
if (mActive == null){
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null){
//真正開始執(zhí)行任務(wù)是在這里
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
- 定義線程池的方法
亮點在于:靜態(tài)化構(gòu)造線程池,這樣當(dāng)構(gòu)建對象時等太,會初始化線程池
//獲取當(dāng)前CPU核心數(shù)
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;
//自定義工廠方法捂齐,標(biāo)記線程,以便管理
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
//任務(wù)隊列
private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<>(128);
//線程池
public static final Executor THREAD_POOL_EXECUTOR;
//構(gòu)造一個線程池
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;
}
- 關(guān)于不定參數(shù)的使用
private static class AsyncTaskResult<Data>{
final AsyncTask mTask;
final Data[] mData;
public AsyncTaskResult(AsyncTask mTask, Data... mData) {
this.mTask = mTask;
this.mData = mData;
}
}
使用不定參數(shù)的目的在于在構(gòu)造這樣的類時缩抡,傳入的Data數(shù)據(jù)類型可變:
private Result postResult(Result result){
//創(chuàng)建消息
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
}
protected final void publishProgress(Progress... values){
if (!isCancelled()){
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
如上辛燥,我們可以看到構(gòu)造AsyncTaskResult對象時,既可以傳入單個對象,也可以傳入數(shù)組對象挎塌。