今天偶然想到了使用AsyncTask異步任務(wù)棧,可以在onPostExecute()中修改UI,這不是一個(gè)很奇怪的現(xiàn)象嗎怎披?于是便萌發(fā)想法看看源碼這到底是怎么回事。
一瓶摆、AsyncTask的使用介紹
還記得AsyncTask的使用方法不钳枕?主要是重寫幾個(gè)方法
protected void onPreExecute() //開始前
protected void onProgressUpdate() //進(jìn)行中
protected Object doInBackground() //后臺(tái)執(zhí)行的具體邏輯
protected void onPostExecute() //任務(wù)執(zhí)行完畢
protected void onCancelled() //任務(wù)取消
// Using an AsyncTask to load the slow images in a background thread
new AsyncTask<ViewHolder, Void, Bitmap>() {
private ViewHolder v;
@Override
protected Bitmap doInBackground(ViewHolder... params) {
v = params[0];
return mFakeImageLoader.getImage();
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (v.position == position) {
// If this item hasn't been recycled already, hide the
// progress and set and show the image
v.progress.setVisibility(View.GONE);
v.icon.setVisibility(View.VISIBLE);
v.icon.setImageBitmap(result);
}
}
}.execute(holder);
二、源碼中找答案
-
AsyncTask在其中打開Structure視圖赏壹,馬上就看到了有個(gè)getHandler()方法還有一個(gè)成員變量InternalHandler鱼炒。于是馬上猜測AsyncTask,其實(shí)是使用了Handler機(jī)制實(shí)現(xiàn)了線程切換蝌借。
image 繼續(xù)看InternalHandler的源碼昔瞧,已經(jīng)發(fā)現(xiàn)端倪,它已經(jīng)直接調(diào)用了onProgressUpdate()方法菩佑。
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;
}
}
}
- finish方法里有什么呢自晰?繼續(xù)看,果然調(diào)用onPostExecute()方法稍坯,至此酬荞,基本已經(jīng)確定AsyncTask能夠在回調(diào)中修改UI就是使用了Handler機(jī)制。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
- 什么時(shí)候向Handler發(fā)的消息呢瞧哟?看AsyncTask構(gòu)造方法就可以了混巧。構(gòu)造方法里初始化了工作線程和FutureTask。
public AsyncTask() {
//創(chuàng)建一個(gè)工作線程
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result); //執(zhí)行完了調(diào)用postResult
}
};
//放入FutureTask中
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);
}
}
};
}
- 在executeOnExecutor方法中開始執(zhí)行勤揩。
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); //exec是傳入的線程池
return this;
}
- 最后看下第4步中的postResult()方法的源碼咧党,找到怎么給Handler發(fā)消息的。到這里整個(gè)鏈條已經(jīng)串起來陨亡。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget(); //發(fā)送消息
return result;
}
三傍衡、總結(jié)
AsyncTask并沒有違反Android定義的非UI線程不能修改UI的規(guī)則,實(shí)際上它是使用了Handler機(jī)制實(shí)現(xiàn)了線程切換负蠕。在onPostExecute() 實(shí)際上已經(jīng)處于UI線程當(dāng)中蛙埂,所以可以對(duì)UI進(jìn)行修改,同理于onProgressUpdate()方法遮糖。