我所理解的asynctask

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

RUNNINGFINISHEDAsyncTask的狀態爲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(),任務結束。

當然雖說AsynctaskHandler進行了很好的封裝但是其任然有很多缺點例如:

(1)很多人以爲Asynctask會在Activity銷燬的時候同時銷燬,實際上Asynctaskactivity銷燬的時候有可能不會被銷燬,會一直執行到DoInBackground()執行完畢纔會被銷燬,同時如果Activity被銷燬也有可能造成Asynctask的崩潰,有可能Asynctask操作的View已經被回收造成Asynctask異常。

(2)Asynctaskactivity的非靜態內部類中定義的時候會持有當前activity的引用,即使我們銷燬了當前Activity但是Asynctask仍然會在後臺運行,此時當前Activity無法被回收造成內存泄漏。

(3)Asynctask還有可能會丟失運行的結果,例如屏幕旋轉或者後臺的activity重新被創建,那麼Asynctask持有的是之前的Activity的引用,這時調用onPostExecute更新界面將沒有作用。

以上就是我對Asynctask的理解了如有理解錯誤之處還望批評指正。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章