優缺點:
優點
它封裝了Handler,使創建異步任務變得更加簡單,相較于Handler+Thread的模式,不再需要編寫任務線程和Handler實例即可完成相同的任務。
缺點
- 不適合長時間的后臺操作(適合幾秒鐘的操作)
- AsyncTask的生命周期沒有跟Activity的生命周期同步
AsyncTask不會隨著activity的銷毀而銷毀,它會一直執行, 直到doInBackground()方法執行完畢。如果在Activity銷毀之前,沒有取消 AsyncTask,有可能讓我們的AsyncTask崩潰(crash)。因為它在onPostExecute()中想要處理的view已經不存在了。所以,我們總是必須確保在銷毀活動之前取消任務。
另外,即使我們正確地調用了cancle() 也未必能真正地取消任務。因為如果在doInBackgroud里有一個不可中斷的操作,比如BitmapFactory.decodeStream(),那么這個操作會繼續下去。 - 容易內存泄漏
如果AsyncTask被聲明為Activity的非靜態的內部類,那么AsyncTask會保留一個對創建了AsyncTask的Activity的引用。如果Activity已經被銷毀,AsyncTask的后臺線程還在執行,它將繼續在內存里保留這個引用,導致Activity無法被回收,引起內存泄露。 - 結果丟失
屏幕旋轉或Activity在后臺被系統殺掉等情況會導致Activity的重新創建,之前運行的AsyncTask會持有一個之前Activity的引用,這個引用已經無效,這時調用onPostExecute()再去更新界面將不再生效。
要注意的地方:
- 并行還是串行
在Android 1.6之前的版本,AsyncTask是串行的,在1.6至2.3的版本,改成了并行的。在2.3之后的版本又做了修改,可以支持并行和串行,當想要串行執行時,直接執行execute()方法,如果需要并行執行,則要執行executeOnExecutor(Executor)。 - 在activity的destroy()中執行cancel()后,AsyncTask將執行完doInBackground(),但不再執行onPostExecute()和onProgressUpdate(),而是執行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的執行流程,現在我們通過源碼并且結合上述案例,對AsyncTask做更為細致的分析:
一、 首先我們是在主線程上創建了一個繼承AsyncTask的MyAsynTask類: MyAsynTask myAsynTask = new MyAsynTask();由于是繼承關系,上述方法執行了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;我們跟進去,發現實際的執行是: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狀態,如果是正在運行(RUNNING)或者已經結束運行(FINISHED),就會拋出異常。
- 接著設置狀態為運行,執行onPreExecute()方法,并把參數的值賦給mWorker.mParams;
- 于是Executor去執行execute的方法,學過java多線程的都知道。這個方法是開啟一個線程去執行mFuture中的run()方法
- 注意mFuture和mWorker都是在AsyncTask的構造方法中初始化過的
三、根據上述講解,將執行mFuture的run,也就是將執行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);
}
- 設置最高優先級,接著執行了doInBackground()方法,注意它的參數mParams正是mWorker的屬性mParams,而我們在之前有過這樣的代碼:mWorker.mParams = params;因此doInBackground方法的參數就是execute方法傳遞的參數
- 好了,執行到了我們重寫的doInBackground()方法了,現在要回到MyAsynTask類中的來了,在doInBackground中執行了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);得到執行,那么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;
}
看到沒有,發送了MESSAGE_POST_RESULT信息,于是在第六步中的handleMessage方法的代碼中result.mTask.finish(result.mData[0])得到執行,在這個方法中,執行了AsyncTask的finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
在這代碼中,如果沒有取消,那么就執行onPostExecute方法,記得result是什么嗎?Result result = doInBackground(mParams);正是doInBackground方法返回的結果
最后將狀態設置為Status.FINISHED,還記得我們在AsyncTask的簡要說明的第四點說過嗎?一個任務實例只能執行一次,如果執行第二次將會拋出異常,因為執行完一次之后,狀態變成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)時,系統會發送MESSAGE_POST_RESULT信息,也就是提前進入了上述第五步:執行如下代碼
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
由于設置了onCancelled(true),所以onCancelled(result)方法得到執行。之后再設置狀態為Status.FINISHED;
建議閱讀
Java多線程:Executor,Executors,Future,Callable,Runnable等