AsyncTask 完全解析

AsyncTask 完全解析

引言

我們知道,在 Android 中,UI 線程不能執(zhí)行耗時操作;在子線程中不能執(zhí)行更新 UI 的操作。如果需要在子線程中進行 UI 相關(guān)的操作,那么就需要借助 Android 中的異步消息機制(比如我們熟悉的Handler消息機制)才能完成。如果我們自己寫代碼來進行相關(guān)的處理,不僅麻煩,而且大部分的代碼都是相同的,AsyncTask 的出現(xiàn)就能幫我們省去大部分的代碼,并且可以非常靈活方便地從子線程切換到UI線程。今天就從 AsyncTask 的簡單使用到源碼進行解析,一步一步看看他是怎么實現(xiàn)的。

AsyncTask 的簡單使用

創(chuàng)建 AsyncTask 實現(xiàn)類

class DownLoadAsyncTask extends AsyncTask<String, Integer, Boolean> {
    @Override
    protected Boolean doInBackground(String... params) {
        // 運行在子線程,執(zhí)行訪異步任務
        Log.i("DownLoadAsyncTask", "doInBackground(): 開始執(zhí)行異步任務");
        // publishProgress(Integer); // 調(diào)用更新進度方法
        return downLoadImage(params[0]); // 下載圖片方法
    }

    @Override
    protected void onPreExecute() {
        // 運行在主線程,異步任務執(zhí)行前的準備工作
        Log.i("DownLoadAsyncTask", "onPreExecute(): 執(zhí)行異步任務前的準備工作");
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(Boolean result) {
        // 運行在主線程,異步任務執(zhí)行完成之后的回調(diào)
        Log.i("DownLoadAsyncTask", "onPostExecute(): 異步任務執(zhí)行完成之后的回調(diào) => " + result);
        super.onPostExecute(result);
    }

    @Override
    protected void onProgressUpdate(Integer... progresses) {
        // 運行在主線程,用于更新進度
        // 注意:該方法需要在doInBackground()內(nèi)部調(diào)用publishProgress()方法并傳遞進度,否則不會執(zhí)行
        Log.i("DownLoadAsyncTask", "onProgressUpdate(): 用于更新進度");
        super.onProgressUpdate(progresses);
    }
}

AsyncTask<String, Integer, Boolean> 泛型說明:

  1. 第一個泛型:doInBackground() 方法的參數(shù)類型
  2. 第二個泛型:onProgressUpdate() 方法的參數(shù)類型
  3. 第三個泛型:doInBackground() 方法的返回類型 和 onProgressUpdate() 方法的參數(shù)類型

開始執(zhí)行任務

String url = "https://www.baidu.com/img/bd_logo1.png";
DownLoadAsyncTask downLoadAsyncTask = new DownLoadAsyncTask();
downLoadAsyncTask.execute(url);

以上就是 AsyncTask 的基本用法。

源碼解析

構(gòu)造方法

public AsyncTask() {
    this((Looper) null);
}

public AsyncTask(@Nullable Handler handler) {
    this(handler != null ? handler.getLooper() : null);
}

/**
 * @hide
 */
public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
        ? getMainHandler()
        : new Handler(callbackLooper);

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

構(gòu)造方法說明:

  1. 最終調(diào)用的都是AsyncTask(@Nullable Looper callbackLooper)方法,但是這個方法使用了@hide注解,開發(fā)者并不能直接調(diào)用。構(gòu)造方法雖然比較長,但是他并沒有任何的操作被執(zhí)行,只是初始化了mHandlermWorker 、 mFuture幾個變量,并且將 mWorker 對象作為 mFuture 的構(gòu)造方法參數(shù)傳遞給了 mFuture 對象。
  2. mHandler 是MainHandler
  3. 有一點需要注意:構(gòu)造方法只能在UI線程中調(diào)用

構(gòu)造方法中用到的部分對象說明:

  1. mHandler:Android Handler消息機制中的Handler對象,這里是InternalHandler對象,暫時記住就行了,后面會粘貼出具體實現(xiàn)的代碼和說明

    class InternalHandler extends Handler:

  2. mWorker:實現(xiàn) Callable 接口的 AsyncTask 類的內(nèi)部類 WorkerRunnable
  3. mFuture:FutureTask 對象。FutureTask 對象的繼承關(guān)系
    1. class FutureTask<V> implements RunnableFuture<V>
    2. interface RunnableFuture<V> extends Runnable, Future<V>

執(zhí)行異步任務方法

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);// 調(diào)用內(nèi)部方法
}

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params) {
    if (mStatus != Status.PENDING) { // 判斷狀態(tài)
        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; // 將狀態(tài)設置為RUNNING

    onPreExecute(); // 回調(diào)異步任務執(zhí)行前的準備工作方法

    mWorker.mParams = params; // 將傳遞的參數(shù)賦值給 mWorker 對象的 mParams 字段
    exec.execute(mFuture); // 執(zhí)行 mFuture

    return this;

}

到這一步的時候,我們的任務已經(jīng)切換子線程中了。

方法說明:

  1. 判斷當前的狀態(tài),如果是RUNNING或者是FINISHED就拋出異常
  2. 執(zhí)行回調(diào)方法 onPreExecute() ,執(zhí)行異步任務前的準備工作,比如顯示進度對話框等
  3. mFuture 對象 交給 exec.execute(mFuture) 執(zhí)行

exec.execute(mFuture)說明:

exec:即 sDefaultExecutor;實現(xiàn) Executor接口的內(nèi)部類 SerialExecutor

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

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(); // 調(diào)用參數(shù) Runnable 對象的 run() 方法
                } finally {
                    scheduleNext();
                }
            }
        });
        if (mActive == null) {
            scheduleNext();
        }
    }

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

通過上面 SerialExecutor 類的定義,我們可以看到 execute() 方法調(diào)用了它的參數(shù)(即mFuture)的run()方法,我們繼續(xù)查看mFuturerun() 方法

public void run() {
    if (state != NEW ||
        !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

在該方法中主要是調(diào)用了 callable 對象的 call() 方法,我們一起看看 callable對象是從哪里來的。

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

查看 FutureTask 對象的構(gòu)造方法,我們發(fā)現(xiàn)callable對象是在構(gòu)造方法中初始化的。好,我們現(xiàn)在就只要知道 FutureTask 對象是在哪里初始化的,就知道 call() 方法的具體執(zhí)行內(nèi)容是什么了。那么你是否還記得我們在查看 AsyncTask 類的構(gòu)造方法時看到了它初始化幾個變量就有FutureTask 對象,所以在這里執(zhí)行的 call() 方法具體的方法體就是在AsyncTask 類的構(gòu)造方法總中定義的方法體。為了方便觀察,我把這段代碼在粘貼一次:

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); // 執(zhí)行 doInBackground 回調(diào)方法,參數(shù)在mParams的值在executeOnExecutor()中初始化了
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result); // 設置結(jié)果
            }
            return result;
        }
    };

看了這么久的代碼,我們總算看到了執(zhí)行任務的方法,也就是我們的重寫方法 doInBackground(mParams) 返回的 Result 是結(jié)果泛型類型(第三個泛型的類型),在上面說過了三個泛型表示的意義;也就是說,到了這一步,我們的異步任務真正的開始執(zhí)行了;我們接著看finally中的代碼,調(diào)用的 postResult(result) 方法,看看這個方法的具體實現(xiàn):

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

在這個方法中使用了一個新的類 AsyncTaskResult,它也是 AsyncTask 的內(nèi)部類,定義如下:

private static class AsyncTaskResult<Data> {
    final AsyncTask mTask;
    final Data[] mData;

    AsyncTaskResult(AsyncTask task, Data... data) {
        mTask = task;
        mData = data;
    }
}

回過頭在看 postResult(Result result) 這個方法中的代碼非常簡單,getHandler()方法獲取到我們在構(gòu)造方法中初始化的 mHandler 對象,接著獲取一個 Message 對象并且創(chuàng)建一個 AsyncTaskResult 對象(這個對象包含了AsyncTask 類的本類對象和 doInBackground()方法返回的結(jié)果對象2個參數(shù))作為消息的內(nèi)容,最后將這個消息發(fā)送到目標 mHandler 。上面說過了這個mHandlerInternalHandler,但是沒有貼出具體實現(xiàn)的代碼,那么現(xiàn)在我們就來看一下它到底做了些什么(InternalHandler類是AsyncTask類的內(nèi)部類):

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

這段代碼我想大家都能看懂吧,最常見的 Handler 寫法,通過判斷 Messagewhat 進行不同的操作(任務執(zhí)行完成或者更新進度)。我們只需要弄清楚 result.mTask 表示的哪一個對象就可以知道調(diào)用的方法是什么了。
postResult(Result result)方法中,我們知道了 Messageobj 字段的值是 AsyncTaskResult 對象,參數(shù)是 thisdoInBackground()方法返回的結(jié)果對象,很容易知道this表示 AsyncTask 本類對象;在通過 AsyncTaskResult 的構(gòu)造方法我就知道 result.mTask 就是AsyncTask 的本類對象,所以我們就知道了 result.mTask.finish(result.mData[0]) 方法就是AsyncTask 類的 finish(Result result) 方法了;同理result.mTask.onProgressUpdate(result.mData) 方法就是AsyncTask 類的 onProgressUpdate(Progress... values) 方法。

看看AsyncTask 類的 finish(Result result) 方法:

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

方法說明:

  1. 判斷是不是取消了,如果取消了,就回調(diào) onCancelled() 方法(開發(fā)者重寫)
  2. 如果沒有取消就回調(diào) onPostExecute(Result result) 方法(開發(fā)者重寫)
  3. 將任務的執(zhí)行狀態(tài)改變?yōu)?FINISHED

到此為止,我們發(fā)現(xiàn)的任務執(zhí)行前的準備方法onPreExecute()、任務執(zhí)行方法 doInBackground 以及 取消方法 onCancelled() 和完成方法 onPostExecute() 都成功回調(diào)了;但是我們更新進度的方法 onProgressUpdate() 卻并沒有在哪里有調(diào)用;如果看的比較知仔細的可能已經(jīng)發(fā)現(xiàn)了,我在第一部分簡單使用中說明了:

更新進度回調(diào).png

那么我們看看 publishProgress(Progress... values) 方法:

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

它和 postResult(Result result) 方法是一樣的,發(fā)送一個消息,就不在多說了,回過頭看一下就知道了。

以上就是 AsyncTask 的主要執(zhí)行過程。

相關(guān)文章

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

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

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