AsyncTask的使用和工作原理

簡(jiǎn)介

AsyncTask是一個(gè)輕量級(jí)的異步任務(wù)類,封裝了Handler和Thread,可以方便的在線程池里執(zhí)行后臺(tái)任務(wù),并把進(jìn)度和結(jié)果發(fā)送到主線程并在主線程中更新UI。AsyncTask應(yīng)該用來(lái)執(zhí)行比較短的后臺(tái)任務(wù),一般是以秒為單位的。如果需要保持線程長(zhǎng)期運(yùn)行,建議用線程池進(jìn)行。

一個(gè)AsyncTask是一個(gè)抽象的泛型類,通過(guò)繼承的方式來(lái)使用。AsyncTask需要指定三個(gè)三個(gè)泛型參數(shù)的類型,重寫四個(gè)回調(diào)方法。

三個(gè)泛型

三個(gè)泛型參數(shù)分別是Params, Progress and Result。

  • Params:初始化AsyncTask時(shí)傳入的參數(shù)類型,用來(lái)定義傳遞給后臺(tái)任務(wù)的參數(shù)類型。
  • Progress:后臺(tái)任務(wù)執(zhí)行進(jìn)度的類型。
  • Result:后臺(tái)任務(wù)執(zhí)行完成返回的結(jié)果類型。

當(dāng)不需要相應(yīng)的參數(shù)的時(shí)候,也可定義成Void類型。

四個(gè)方法

  • onPreExecute(),后臺(tái)任務(wù)執(zhí)行前在UI線程中調(diào)用,一般用來(lái)做一些初始化工作,比如顯示progress bar等。
  • doInBackground(Params...),在onPreExecute()方法執(zhí)行之后,在后臺(tái)線程中調(diào)用,用來(lái)處理耗時(shí)的后臺(tái)任務(wù),執(zhí)行完成之后將結(jié)果return。在這個(gè)方法中可以調(diào)用publishProgress(Progress...)將執(zhí)行進(jìn)度發(fā)送到主線程的回調(diào)方法onProgressUpdate(Progress...)。
  • onProgressUpdate(Progress...),在調(diào)用publishProgress(Progress...)方法之后會(huì)在主線程中回調(diào)這個(gè)方法。主要用來(lái)更新后臺(tái)任務(wù)的執(zhí)行進(jìn)度。
  • onPostExecute(Result),在后臺(tái)任務(wù)執(zhí)行完成之后在UI線程中調(diào)用。后臺(tái)任務(wù)執(zhí)行結(jié)果會(huì)作為一個(gè)參數(shù)傳遞到這個(gè)方法中,一般用來(lái)更新UI。

取消任務(wù)

AsyncTask可以調(diào)用cancel(boolean)方法取消執(zhí)行,該方法調(diào)用之后,調(diào)用isCancelled()方法會(huì)返回true,后臺(tái)任務(wù)執(zhí)行完成后,不再調(diào)用onPostExecute(Object),而是調(diào)用onCancelled(Object)。為了盡快的取消任務(wù),應(yīng)該在doInBackground(Object[])方法中盡可能的調(diào)用isCancelled()判斷任務(wù)是否被取消。

使用方法

AsyncTask必須通過(guò)繼承的方式使用。子類至少?gòu)?fù)寫onInBackground(Params...)方法,一般還會(huì)復(fù)寫onPostExecute(Result)方法。如下使用一個(gè)模擬下載文件的例子:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

寫好子類之后,執(zhí)行就比較簡(jiǎn)單。

new DownloadFilesTask().execute(url1, url2, url3);

注意事項(xiàng)

AsyncTask使用有一些限制,需要注意:

  • AsyncTask類必須在UI線程中加載。在Android4.1之后由系統(tǒng)自動(dòng)完成。
  • AsyncTask實(shí)例必須在UI線程中創(chuàng)建。
  • execute(Params...)方法必須在UI線程中調(diào)用。
  • 不要手動(dòng)調(diào)用提供的四個(gè)回調(diào)方法。
  • 每個(gè)AsyncTask實(shí)例只能執(zhí)行一次。

版本演化

AsyncTask類經(jīng)過(guò)幾次的版本演化,一開(kāi)始的AsyncTask是順序執(zhí)行的,從Android1.6開(kāi)始,改成了線程池,允許多個(gè)AsyncTask并行執(zhí)行。直到Android3.0開(kāi)始,為了避免并發(fā)引起的錯(cuò)誤,AsyncTask又改成默認(rèn)為順序執(zhí)行,但可以通過(guò)executeOnExecutor()方法并發(fā)執(zhí)行。

AsyncTask的工作原理

為了分析AsyncTask的工作原理,從execute(Params... params)方法入手。

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}

execute(Params... params)方法又調(diào)用了executeOnExecutor(Executor exec, Prams... 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;
}

從上面的源碼可以看到,在AsyncTask執(zhí)行的時(shí)候,就調(diào)用了onPreExecute()方法,然后將params參數(shù)封裝成FutureTask對(duì)象,調(diào)用了線程池sDefaultExecutor的execute(mFuture)方法。線程池sDefaultExecutor實(shí)際就是一個(gè)串行的線程池,我們來(lái)看一下sDefaultExecutor線程池的實(shí)現(xiàn)。

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

從這里可以看到,在SerialExecutor中,F(xiàn)utureTask作為Runnable對(duì)象傳進(jìn)來(lái)之后,會(huì)把FutureTask插入任務(wù)隊(duì)列mTasks中,如果當(dāng)前沒(méi)有正在活動(dòng)的AsyncTask,就會(huì)調(diào)用sheduleNext()方法,如果有正在活動(dòng)的AsyncTask,則在執(zhí)行結(jié)束之后調(diào)用sheduleNext()方法,直到所有的任務(wù)執(zhí)行完成。可以看得出來(lái)SerialExecutor是串行執(zhí)行的。而真正執(zhí)行的線程池為THREAD_POOL_EXECUTOR,SerialExecutor是對(duì)THREAD_POOL_EXECUTOR的封裝。

在THREAD_POOL_EXECUTOR的execute()方法中最后調(diào)用了run方法。

public void run() {
    ...
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
    ...
}

而在FutureTask執(zhí)行run方法時(shí),會(huì)執(zhí)行Callable的call()方法,從AsyncTask的構(gòu)造方法中可以發(fā)現(xiàn),對(duì)應(yīng)的是mWorker的call()方法。

mWorker = new WorkerRunnable<Params, Result>() {
    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;
    }
};

mFuture = new FutureTask<Result>(mWorker) {
...

在call()方法中,執(zhí)行了doInBackground(mParams)方法,然后將返回值傳遞給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;
}

而在postResult(Result)方法中,將result包裝成Message,發(fā)送給Handler,跟蹤getHandler()找到對(duì)應(yīng)的Handler為InternalHandler。

private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }

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

InternalHandler收到MESSAGE_POST_RESULT消息之后,調(diào)用AsyncTask的finish()方法。

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

如果AsyncTask取消執(zhí)行了,就調(diào)用onCancelled()方法,否則調(diào)用onPostExecute()方法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容