資料
概述:
Android中试疙,實現(xiàn)異步有兩種方式柳弄,Handler和AsyncTask。
使用Handler+Thread時两蟀,每次執(zhí)行耗時操作都需要創(chuàng)建新的線程進(jìn)行處理网梢,代碼比較臃腫,性能開銷也會較大赂毯。
使用AsyncTask战虏,內(nèi)部是封裝好的Handler+Thread,并且使用了線程池党涕,有效的優(yōu)化了性能烦感。
"AsyncTask并不適合進(jìn)行特別耗時的后臺任務(wù),對特別耗時的任務(wù)膛堤,建議使用線程池手趣。--開發(fā)藝術(shù)探索上所寫,但是還并未理解"
可能是因為:多個任務(wù)時特別耗時的任務(wù)會影響后面的任務(wù)遲遲不能執(zhí)行肥荔。用線程池并發(fā)的話绿渣,就沒這樣的問題了朝群。
原理:
輕量級的異步任務(wù)類,在線程池中串行執(zhí)行任務(wù)中符,通過Handler把進(jìn)度和執(zhí)行結(jié)果發(fā)送到主線程姜胖,更新UI。
簡單使用:
MyAsyncTask mAsyncTask = new MyAsyncTask();
mAsyncTask.execute();//下面后臺任務(wù)參數(shù)為Void類型淀散,所以不填參數(shù)右莱。
/**
*AsyncTask<Void, Integer, Boolean>:泛型,可以為任意類型吧凉。
*分別為:后臺任務(wù)執(zhí)行的參數(shù)隧出,更新進(jìn)度的參數(shù),任務(wù)執(zhí)行完成的結(jié)果
*/
public class MyAsyncTask extends AsyncTask<String, Integer, Boolean>{
private ProgressDialog mProgress;
private int currentProgress;
//任務(wù)開始前的準(zhǔn)備操作阀捅,可以做些UI的準(zhǔn)備或初始化胀瞪。
//多個任務(wù)時,無論是否等待饲鄙,execute()的時候就在主線程調(diào)用
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgress.setMax(100);
mProgress.setMessage("下載進(jìn)度");
mProgress.show();
}
//線程池中執(zhí)行任務(wù)
@Override
protected Boolean doInBackground(Void... params) {
while (currentProgress <= 100) {
//不能跟新UI
//mProgress.setProgress(currentProgress);
//想更新進(jìn)度的話凄诞,主動調(diào)用該方法,會通過handler給onProgressUpdate方法忍级。
publishProgress(currentProgress);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
return false;
}
currentProgress++;
}
return true;
}
//publishProgress通過handler調(diào)用帆谍,主線程
@Override
protected void onProgressUpdate(Integer... values) {
mProgress.setMessage("下載進(jìn)度:"+values[0]);
}
//執(zhí)行完成后的結(jié)果。
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
if (aBoolean) {
mProgress.setMessage("下載完成");
}else {
mProgress.setMessage("下載出錯");
}
mProgress.cancel();
}
//中斷任務(wù)時轴咱,調(diào)用該方法汛蝙。但并不一定會馬上中斷。
@Override
protected void onCancelled() {
super.onCancelled();
}
}
原理朴肺,源碼分析:
按照調(diào)用方法窖剑,一步一步的分析。
- 構(gòu)造函數(shù)入手:
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
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);
}
}
};
}
好像并不能看出來什么戈稿,就兩個實例對象初始化西土。這里記得就行,從內(nèi)部邏輯上調(diào)用的方法名來看,一個mWorker跟后臺任務(wù)有關(guān)鞍盗;一個mFuture跟結(jié)果通知有關(guān)需了。這里看不懂正常,也不要每步都要求詳細(xì)清楚般甲,往下看肋乍。
- 調(diào)用mAsyncTask.execute()方法:
方法1:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
方法2:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//如果狀態(tài)為正在運行或者已經(jīng)結(jié)束,報錯敷存。說明住拭,只能調(diào)用一次mAsyncTask.execute()方法。
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task: the task is already running.");
case FINISHED://明確說明只能執(zhí)行一次。
throw new IllegalStateException("Cannot execute task: the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;//改變狀態(tài)
//看好了哈滔岳,在此處調(diào)用杠娱。此時還是在主線程中哦,所以可以操作UI谱煤。
onPreExecute();
//構(gòu)造方法中的一個實例摊求,把執(zhí)行后臺任務(wù)的參數(shù)給了它。
mWorker.mParams = params;
//該exec是方法1中的sDefaultExecutor刘离,看下面代碼.
exec.execute(mFuture);
return this;
}
1.只能執(zhí)行一次mAsyncTask.execute()方法室叉。
2.主線程調(diào)用onPreExecute()
3.更改狀態(tài),賦值硫惕。
4.調(diào)用線程池有關(guān)方法執(zhí)行茧痕。sDefaultExecutor.execute(mFuture)
繼續(xù)往下看,調(diào)用的方法:
private static volatile Executor sDefaultExecutor = new SerialExecutor();
//Executor恼除?線程池類踪旷?
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
//mFuture參數(shù),也即是構(gòu)造方法中的實例
public synchronized void execute(final Runnable r) {
//封裝成一個Runnable,放到隊列的最后豁辉。
語句1: mTasks.offer(new Runnable() {
public void run() {
try {
//mFuture的run方法令野,只是調(diào)用方法,run并沒有開新線程
語句5: r.run();
} finally {
語句6: scheduleNext();
}
}
});
//第一次執(zhí)行時
if (mActive == null) {
語句2: scheduleNext();
}
}
protected synchronized void scheduleNext() {
//取出隊列中第一個封裝好的Runnable
語句3: if ((mActive = mTasks.poll()) != null) {
//THREAD_POOL_EXECUTOR是線程池
語句4: THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
執(zhí)行步驟徽级,按語句順序:將mFuture的run方法封裝成Runnable對象放入隊列最后--->第一次執(zhí)行時气破,取出Runnable并到線程池中執(zhí)行--->執(zhí)行完以后,再取餐抢,再去執(zhí)行现使。以此類推...
需要注意:封裝好的Runnable在線程池中會開新的線程。mFuture的run只是一個方法旷痕,也就是說此時run中的代碼已經(jīng)在子線程了碳锈。
上面整個過程都是在放入/取出Runnable,最主要的是執(zhí)行的mFuture的run方法苦蒿。
//FutureTask類殴胧,mFuture的run方法
public void run() {
if (state != NEW || !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
語句1: Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
語句2: result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
語句3: set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
語句1中的callable是構(gòu)造函數(shù)中初始化mFuture的用到的第一個實例mWorker啊渗稍。
語句2執(zhí)行了mWorker的call方法佩迟。
語句3最后執(zhí)行了mFuture的done方法。
語句2,3執(zhí)行的正好是構(gòu)造時兩個實例復(fù)寫的方法:先執(zhí)行call竿屹,再執(zhí)行done报强。
再回過頭來看AsyncTask的構(gòu)造方法:
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
語句0 mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
語句1: result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
語句2: postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
語句3: 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);
}
}
};
}
語句1就是生成AsyncTask實例時復(fù)寫的后臺執(zhí)行任務(wù)的方法:doInBackground() 在線程池中執(zhí)行的。
@WorkerThread
protected abstract Result doInBackground(Params... params);
語句2拿到后臺任務(wù)執(zhí)行后的result拱燃,通過mainHandler調(diào)用onPostExecute(result);
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 void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
protected void onPostExecute(Result result) {
}
另外秉溉,語句3的 postResultIfNotInvoked(get()),如果滿足條件,也會調(diào)用postResult通過handler....
但是召嘶,正是因為語句0的設(shè)置父晶,使其并不滿足條件,所以不執(zhí)行弄跌。(不太清楚wasTaskInvoked的作用)
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
至此甲喝,關(guān)于調(diào)用mAsyncTask.execute()方法,上面的源碼分析完了铛只,先把任務(wù)放入隊列最后埠胖,然后取出隊列第一個,在線程池中調(diào)用了doInBackground淳玩,后通過主線程的handler調(diào)用onPostExecute(Result result);
- publishProgress:該方法可以再doInbackGroud中給onProgressUpdate更新進(jìn)度直撤。上面分析的過程中,程序并不會自動調(diào)用該方法蜕着,需要用到的時候谋竖,我們自己調(diào)用就行了。
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
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;
}
}
protected void onProgressUpdate(Progress... values) {
}
至此侮东,整個AsyncTask執(zhí)行過程就分析完了圈盔。跨度太大悄雅,總結(jié)一下:
1.onPreExecute()在mAsyncTask.execute(...params)執(zhí)行的時候驱敲,馬上執(zhí)行,主線程宽闲。
2.doInBackgroun在線程池中調(diào)用众眨。子線程。
3.得到結(jié)果后容诬,通過主線程的handler發(fā)送消息娩梨,調(diào)用onPostExecute。主線程览徒。
4.手動調(diào)用publishProgress會通過主線程的handler調(diào)用onProgressUpdate狈定。 主線程。