優(yōu)缺點:
優(yōu)點
它封裝了Handler牧愁,使創(chuàng)建異步任務變得更加簡單逞姿,相較于Handler+Thread的模式妻顶,不再需要編寫任務線程和Handler實例即可完成相同的任務。
缺點
- 不適合長時間的后臺操作(適合幾秒鐘的操作)
- AsyncTask的生命周期沒有跟Activity的生命周期同步
AsyncTask不會隨著activity的銷毀而銷毀匈子,它會一直執(zhí)行, 直到doInBackground()方法執(zhí)行完畢河胎。如果在Activity銷毀之前,沒有取消 AsyncTask虎敦,有可能讓我們的AsyncTask崩潰(crash)游岳。因為它在onPostExecute()中想要處理的view已經不存在了。所以原茅,我們總是必須確保在銷毀活動之前取消任務吭历。
另外,即使我們正確地調用了cancle() 也未必能真正地取消任務擂橘。因為如果在doInBackgroud里有一個不可中斷的操作晌区,比如BitmapFactory.decodeStream(),那么這個操作會繼續(xù)下去通贞。 - 容易內存泄漏
如果AsyncTask被聲明為Activity的非靜態(tài)的內部類朗若,那么AsyncTask會保留一個對創(chuàng)建了AsyncTask的Activity的引用。如果Activity已經被銷毀昌罩,AsyncTask的后臺線程還在執(zhí)行哭懈,它將繼續(xù)在內存里保留這個引用,導致Activity無法被回收茎用,引起內存泄露遣总。 - 結果丟失
屏幕旋轉或Activity在后臺被系統殺掉等情況會導致Activity的重新創(chuàng)建,之前運行的AsyncTask會持有一個之前Activity的引用轨功,這個引用已經無效旭斥,這時調用onPostExecute()再去更新界面將不再生效。
要注意的地方:
- 并行還是串行
在Android 1.6之前的版本古涧,AsyncTask是串行的垂券,在1.6至2.3的版本,改成了并行的羡滑。在2.3之后的版本又做了修改菇爪,可以支持并行和串行算芯,當想要串行執(zhí)行時,直接執(zhí)行execute()方法凳宙,如果需要并行執(zhí)行熙揍,則要執(zhí)行executeOnExecutor(Executor)。 - 在activity的destroy()中執(zhí)行cancel()后近速,AsyncTask將執(zhí)行完doInBackground()诈嘿,但不再執(zhí)行onPostExecute()和onProgressUpdate(),而是執(zhí)行onCancelled().
使用:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ProgressDialog mDialog;
private TextView mTextView;
MyAsyncTask myAsyncTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.id_tv);
mDialog = new ProgressDialog(this);
mDialog.setMax(100);
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setCancelable(true);
myAsyncTask = new MyAsyncTask();
myAsyncTask.execute();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (myAsyncTask != null)
myAsyncTask.cancel(true);
}
private class MyAsyncTask extends AsyncTask<Void, Integer, Void> {
@Override
protected void onPreExecute() {
mDialog.show();
Log.e(TAG, Thread.currentThread().getName() + " onPreExecute ");
}
@Override
protected Void doInBackground(Void... params) {
// 模擬數據的加載,耗時的任務
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(80);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(i);
}
Log.e(TAG, Thread.currentThread().getName() + " doInBackground ");
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
mDialog.setProgress(values[0]);
Log.e(TAG, Thread.currentThread().getName() + " onProgressUpdate ");
}
@Override
protected void onPostExecute(Void result) {
// 進行數據加載完成后的UI操作
mDialog.dismiss();
mTextView.setText("LOAD DATA SUCCESS ");
Log.e(TAG, Thread.currentThread().getName() + " onPostExecute ");
}
}
}
效果:
源碼分析:
好了削葱,上述我們基本得到了AsyncTask的執(zhí)行流程奖亚,現在我們通過源碼并且結合上述案例,對AsyncTask做更為細致的分析:
一析砸、 首先我們是在主線程上創(chuàng)建了一個繼承AsyncTask的MyAsynTask類: MyAsynTask myAsynTask = new MyAsynTask();由于是繼承關系昔字,上述方法執(zhí)行了MyAsynTask的父類AsyncTask的構造方法:
public AsyncTask() {
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);
}
};
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);
}
}
};
}
- AsyncTask類初始化了兩個類:mWorker 與mFuture:
- WorkerRunnable是實現了Callable接口的抽象方法;FutureTask實現了RunnableFuture首繁,而RunnableFuture接口繼承了Runnable和Future
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result>
public interface RunnableFuture<V> extends Runnable, Future<V>
public class FutureTask<V> implements RunnableFuture<V>
二作郭、 調用myAsynTask對象的execute()方法,并且傳遞參數huhx弦疮;我們跟進去夹攒,發(fā)現實際的執(zhí)行是: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;
}
- 該方法首先是判斷mStatus狀態(tài),如果是正在運行(RUNNING)或者已經結束運行(FINISHED)胁塞,就會拋出異常咏尝。
- 接著設置狀態(tài)為運行,執(zhí)行onPreExecute()方法啸罢,并把參數的值賦給mWorker.mParams;
- 于是Executor去執(zhí)行execute的方法编检,學過java多線程的都知道。這個方法是開啟一個線程去執(zhí)行mFuture中的run()方法
- 注意mFuture和mWorker都是在AsyncTask的構造方法中初始化過的
三扰才、根據上述講解允懂,將執(zhí)行mFuture的run,也就是將執(zhí)行mWorker的call方法衩匣,如下:
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);
}
- 設置最高優(yōu)先級蕾总,接著執(zhí)行了doInBackground()方法,注意它的參數mParams正是mWorker的屬性mParams琅捏,而我們在之前有過這樣的代碼:mWorker.mParams = params;因此doInBackground方法的參數就是execute方法傳遞的參數
- 好了生百,執(zhí)行到了我們重寫的doInBackground()方法了,現在要回到MyAsynTask類中的來了午绳,在doInBackground中執(zhí)行了publishProgress方法。跟進去映之,我們看一下代碼
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
四拦焚、 上述我們講到了Handler的部分了蜡坊,很自然的我們是不是要看一下Handler的handleMessage方法呢?跟進去赎败,我們看一下
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;
}
}
由于上述傳遞的消息是MESSAGE_POST_PROGRESS秕衙,所以result.mTask.onProgressUpdate(result.mData);得到執(zhí)行,那么result.mTas是什么了僵刮,對了据忘,就是我們的AsyncTask。由于AsyncTaskResult的第二個參數是values是publishProgress的參數搞糕,那么onProgressUpdate中的參數就是publishProgress方法的參數勇吊,如下:
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
五、 好了窍仰,我們要回到第三步的汉规,最后一個postResult(result)方法了,在這個方法當中驹吮,如下
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
看到沒有针史,發(fā)送了MESSAGE_POST_RESULT信息,于是在第六步中的handleMessage方法的代碼中result.mTask.finish(result.mData[0])得到執(zhí)行碟狞,在這個方法中啄枕,執(zhí)行了AsyncTask的finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
在這代碼中,如果沒有取消族沃,那么就執(zhí)行onPostExecute方法频祝,記得result是什么嗎?Result result = doInBackground(mParams);正是doInBackground方法返回的結果
最后將狀態(tài)設置為Status.FINISHED竭业,還記得我們在AsyncTask的簡要說明的第四點說過嗎智润?一個任務實例只能執(zhí)行一次,如果執(zhí)行第二次將會拋出異常未辆,因為執(zhí)行完一次之后窟绷,狀態(tài)變成FINISHED,在executeOnExecutor方法中會有如下判斷:會報異常的咐柜!
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
六兼蜈、對于在任務的取消中那些說明,我們額外去對它的源碼做一些簡單的分析:
調用onCancelled(true)時拙友,系統會發(fā)送MESSAGE_POST_RESULT信息为狸,也就是提前進入了上述第五步:執(zhí)行如下代碼
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
由于設置了onCancelled(true),所以onCancelled(result)方法得到執(zhí)行遗契。之后再設置狀態(tài)為Status.FINISHED;
建議閱讀
Java多線程:Executor辐棒,Executors,Future,Callable,Runnable等