關於AsyncTask使用及原理的一些說明

AsyncTask這個類用的比較多,平時做項目時,一般用在文件下載這一塊多比較多。其使用起來還算方便,實現根本的原理還是Thread + Handler。這篇文章就來談談AsyncTask的基本使用以及其原理實現,同時說說其和Handler的關係。

1、AsyncTask的基本使用

使用AsyncTask都得實現一個AsyncTask的子類,並在其中重載AsyncTask的一些方法(publishProgress不需要重載,也不能重載,這裏放在一起講),下面就來對這些方法做一些介紹。

protected void onPreExecute()

這個方法主要是在異步執行前去執行一些初始化的工作,因爲onPreExecute方法實際上是執行在主線程,所以可以在其中執行一些界面操作。

protected abstract Result doInBackground(Params... params)

這個放是一個異步方法了,也就是說它不是在主線程中執行,故不能再其中執行界面操作,但是由於其是異步方法所以一般在方法體內執行一些耗時操作,不如文件下載等。

protected final void publishProgress(Progress... values)

這個方法用來在doInBackground方法的中拋出進度數據,並通過傳遞Handler消息,將數據傳到後面要講的onProgressUpdate方法中。

protected void onProgressUpdate(Progress... values)

上面說了,這個方法接收來自publishProgress方法傳遞過來的數據,並且由於通過Handler機制接收的數據,所以onProgressUpdate這個方法實際是在主線程中執行的,所以能在其中進行界面操作,一般我們在這個方法體中操作進度條。

protected void onPostExecute(Result result)

doInBackground方法執行完畢後會調用改方法,並且由於doInBackground也是通過Handler機制給onPostExcute傳遞數據,所以在這個方法中也可以操作界面。

protected void onCancelled()

protected void onCancelled(Result result)

這兩個方法沒啥好說的,也就是取消doInBackground的執行,進而阻斷整個異步過程。

另外我們看看AsyncTask類的聲明

public abstract class AsyncTask<Params, Progress, Result> 

對比這裏的泛型參數和以上幾個方法的參數,我們很容易知道,

Params是doInBackground接收的參數類型

Progress是publishProgress以及onProgressUpdate兩個方法接收的參數類型

Result是onPostExecute以及onCancelled接收的參數類型

2、AsyncTask工作原理說明

第一小節說明了AsyncTask子類需要重載(或者可以重載)的一些方法,當定義好子類後便可通過子類的實例執行execute方法便可以啓動任務運行。

execute方法會執行到下面方法中

@MainThread
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;
}

這裏是一個主線程,並在其中執行了onPreExecute方法,這就是我們前面說的onPreExecute執行在主線程中的原因。接着會通過一個線程管理器來執行mFuture,這個mFuture是一個Runable子類實例。

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);
        }
    }
};

而exec.execute(mFuture)方法會執行到FutureTask.run方法,在執行run方法中有以下代碼

try {
    result = c.call();
    ran = true;
} catch (Throwable ex) {
    result = null;
    ran = false;
    setException(ex);
}
if (ran)
    set(result);

這個代碼中的c.call()方法調用上面mWorker中的call方法,並在其中執行doInBackground並返回result,然後run方法中接着調動set(result)將result值賦給FutureTask.outcome對象。

run方法最終會執行會mFuture的done方法中來,再看done方法裏的postResultIfNotInvoked(get())方法這裏有個get()方法獲取FutureTask.outcome對象(也就是doInBackground方法返回的result值),然後postResultIfNotInvoked方法會執行到以下postResult方法

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

到這裏我們看到使用了Handler機制來傳遞消息了,那麼接受消息的Handler呢就是下面這位大哥了

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;
        }
    }
}

它會根據傳過來的MESSAGE_POST_RESULT去執行finish方法,我們再跟一下

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

當沒有執行cancel操作時,finish方法會執行onPostExecute方法並獲取doInBackground傳遞過來的值。

以上代碼我們說清楚了onPreExecute、doInBackground、onPostExecute這幾個方法。

接着我們看看當調用publishProgress方法時,執行如下代碼

@WorkerThread
protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

我們看到這裏還是使用了Handler機制,並傳MESSAGE_POST_PROGRESS消息,對比上面的Handler,我們知道Handler接受到消息後會執行onProgressUpdate方法。

這裏便講清了publishProgress方法同onProgressUpdate方法之間的關係。

最後,當在執行過程中進行cancel操作時,會在執行上面的finish方法是執行到onCancelled方法中去而不是執行onPostExecute方法。

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

這樣就說清了onCancelled方法。

3、參考文獻

1、詳[解Android中AsyncTask的使用](http://blog.csdn.net/liuhe688/article/details/6532519)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章