在Android中有兩種十分常見的異步處理消息的機制,一種是Handler機制一種是asynctask機制,Handler機制有其缺點:
(1)代碼臃腫
(2)每一個任務都需要開啓一個線程
(3)在多任務同時執行的時候不容易對任務進行控制。
其實asynctask是對Handler的封裝,這一點我們可以再asynctask的源碼中講到,首先看一下如何簡單的使用asynctask。代碼如下
public class MyAsyncTask
extends AsyncTask<String ,String,String> {
//在調用execute之後立馬被調用
private static final
String TAG
= "MyAsyncTask";
@Override
protected void
onPreExecute() {
Log.e(TAG,
"onPreExecute: " +Thread.currentThread());
super.onPreExecute();
}
//後臺執行的邏輯代碼,不能更新UI
@Override
protected
String doInBackground(String... params) {
//執行publishProgress後立馬調用onProgressUpdate
Log.e(TAG,
"doInBackground: " +Thread.currentThread());
publishProgress("d");
return null;
}
//更新UI
@Override
protected void
onProgressUpdate(String... values) {
Log.e(TAG,
"onProgressUpdate: " +Thread.currentThread());
super.onProgressUpdate(values);
}
//返回的結果顯示在UI控件上
@Override
protected void
onPostExecute(String s) {
Log.e(TAG,
"onPostExecute: " +Thread.currentThread());
super.onPostExecute(s);
}
//在任務中途取消任務,更新UI。
@Override
protected void
onCancelled() {
super.onCancelled();
}
然後就是在MainActivity中我們要實例化一個AsyncTask,代碼如下所示。
MyAsyncTask myAsyncTask =new
MyAsyncTask();
myAsyncTask.execute("a");
最後執行結果
可以看到AsyncTask依次執行了onPreExecute()、doInBackground()、onProgressUpData()、onPostExecute()。其中只有doInBackground()是在AsyncTask線程中執行的其他均在UI線程中執行。那麼他們之間是如何相互調用的呢?
首先我們從mainactivity中的execute進入AsyncTask看一看。在AsyncTask中首先調用了executeOnExecutor()方法。
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;
}
在該方法中首先判斷了當前AsyncTask的狀態,AsyncTask有三種狀態,這三種狀態在AsyncTask的內部內Status中有體現三種狀態分別爲PENDING
,RUNNING,FINISHED,當AsyncTask的狀態爲RUNNING,和FINISHED的時候拋出異常,由此可知Asynctask每一次實例化只能被執行一次,如果多次執行會拋出異常。當Asynctask的狀態是PENDING的時候,會首先將狀態更改爲RUNNING,接着重點來了我們上面說到執行execute的時候會立馬執行onPreExecute(),但是我們發現沒有接着執行doInBackground()方法啊,不要急我們接着看mWorker,最後發現mWorker,是一個WorkerRunnable類型的,他重寫了call()方法。
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;
}
在call()中我們看到了doInBackground()在這裏被調用了。當我們在doInBackground()中調用publishProgress("d")的時候
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
可以看到Handler發送了一個消息,這也解釋了爲什麼說Asynctask是對Handler的封裝,這個Handler是InternalHandler中定義的
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:消息,在這裏Asynctask執行了onProgressUpDate(),當任務執行完畢的時候發送MESSAGE_POST_RESULT這時候執行finish()將數據發送給onPostExecute(),任務結束。
當然雖說Asynctask對Handler進行了很好的封裝但是其任然有很多缺點例如:
(1)很多人以爲Asynctask會在Activity銷燬的時候同時銷燬,實際上Asynctask在activity銷燬的時候有可能不會被銷燬,會一直執行到DoInBackground()執行完畢纔會被銷燬,同時如果Activity被銷燬也有可能造成Asynctask的崩潰,有可能Asynctask操作的View已經被回收造成Asynctask異常。
(2)Asynctask在activity的非靜態內部類中定義的時候會持有當前activity的引用,即使我們銷燬了當前Activity但是Asynctask仍然會在後臺運行,此時當前Activity無法被回收造成內存泄漏。
(3)Asynctask還有可能會丟失運行的結果,例如屏幕旋轉或者後臺的activity重新被創建,那麼Asynctask持有的是之前的Activity的引用,這時調用onPostExecute更新界面將沒有作用。
以上就是我對Asynctask的理解了如有理解錯誤之處還望批評指正。