本文簡單介紹Android中的AsyncTask,并從源碼角度分析它的流程和特點。

AsyncTask有助于使用UI線程。
這個類能讓你不主動使用多線程或Handler,在UI線程進行后臺操作并發布結果。
是一個在不用多線程和Handler的情況下的幫助類。AsyncTask適用于短時間的操作(最多幾秒)。
如需長時間的線程操作,建議使用多線程包java.util.concurrent中的API,比如Executor,ThreadPoolExecutor 和 FutureTask

AsyncTask任務的構成:

  • 3種泛型:Params, Progress 和 Result

  • 4個步驟:onPreExecutedoInBackgroundonProgressUpdate 和 onPostExecute

Google文檔

用法簡介

虛構一個計算任務

    /**     * 虛擬的計算任務     */
    private class CalculationTask extends AsyncTask<Float, Integer, Float> {        protected Float doInBackground(Float... inputs) {
            Log.d(TAG, "doInBackground thread ID = " + Thread.currentThread().getId());            long step = 0;            float result = 0;            for (float f : inputs) {                // 假設這里有一些耗時的操作
                result += f;
            }            while (step < 5) {
                result += step;
                step++;                publishProgress((int) step);
            }            return result;
        }        protected void onProgressUpdate(Integer... progress) {
            Log.d(TAG, "onProgressUpdate thread ID = " + Thread.currentThread().getId());
            Log.d(TAG, "onProgressUpdate: " + progress[0]);
        }        protected void onPostExecute(Float result) {
            Log.d(TAG, "onPostExecute thread ID = " + Thread.currentThread().getId());
            Log.d(TAG, "任務執行完畢");
        }
    }    // 執行任務
    new CalculationTask().execute(1.2f, 2.3f, 6.3f);/*logcatMain thread ID = 1doInBackground thread ID = 8089onProgressUpdate thread ID = 1onProgressUpdate: 1...onProgressUpdate thread ID = 1onProgressUpdate: 5onPostExecute thread ID = 1任務執行完畢*/

AsyncTask 使用的的泛型

AsyncTask使用的3種泛型

  • Params 送去執行的類型

  • Progress 后臺計算的進度類型

  • Result 后臺計算的結果

不用的泛型可以用Void表示。例如

private class MyTask extends AsyncTask<Void, Void, Void> { ... }

異步任務的4個步驟

異步任務執行時經過4個步驟

  • onPreExecute() UI線程在任務開始前調用這個方法。此方法常用來設置任務,比如在屏幕上顯示一個進度條。

  • doInBackground(Params...) onPreExecute()執行完畢后立即在后臺線程中執行。這一步用來執行耗時的后臺計算。
    這個方法接受異步任務的參數,返回最后的任務結果。這一步可以調用publishProgress(Progress...)通知出去一個或多個進度。這些進度值會被onProgressUpdate(Progress...)在UI線程收到。

  • onProgressUpdate(Progress...) 調用publishProgress(Progress...)后會在UI線程中執行。用來顯示執行中任務的UI。

  • onPostExecute(Result) 后臺任務執行完畢時被調用。最終結果會被傳入這個方法。

取消任務

調用cancel(boolean)可隨時取消任務。取消任務后isCancelled()會返回true。
調用這個方法后,后臺任務doInBackground(Object[])執行完畢后會調用onCancelled(Object)而不再是onPostExecute(Object)。
為保證任務能被及時地取消,在doInBackground(Object[])中應該經常檢查isCancelled()返回值

線程規則 Threading rules

一些線程規則

  • 異步任務必須從UI線程啟動

  • 必須在UI線程實例化AsyncTask類

  • 必須在UI線程調用execute(Params...)

  • 不要手動調用onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)

  • 同一個異步任務實例只能被執行一次。重復執行同一個異步任務實例會拋出異常(IllegalStateException)。

源碼簡析

需要解決的問題:
AsyncTask是如何調用后臺線程完成任務的?線程是如何調度的?

AsyncTask使用Executor,利用WorkerRunnableFutureTask來執行后臺任務

    private final WorkerRunnable<Params, Result> mWorker; // 實現了 Callable
    private final FutureTask<Result> mFuture;    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }

使用Handler來進行線程調度。內部定義了一個類InternalHandler。

execute(Params... params)方法切入

先看方法execute(Params... params),使用默認執行器,并傳入參數
調用xecuteOnExecutor(Executor exec, Params... params)

    @MainThread // 指定在主線程執行
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);
    }

先判斷當前狀態,如果狀態不是Status.PENDING,則拋出異常。
否則進入Status.RUNNING狀態,執行onPreExecute(),再由執行器啟動任務。

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

mWorker帶著傳進來的參數,mFuture實例化時已經將mWorker注入。參看構造函數

    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                // 在后臺線程進行自定義的操作  這里面可以調用publishProgress方法
                Result result = doInBackground(mParams); 
                Binder.flushPendingCommands();                return postResult(result); // 發送最終結果
            }
        };

        mFuture = new FutureTask<Result>(mWorker) { // 依賴 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);
                }
            }
        };
    }

publishProgress方法通過主線程的Handler向外通知進度

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

后臺任務執行完畢,postResult發送最終結果

    private Result postResult(Result result) {        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget(); // 會走到finish方法
        return result;
    }    private void finish(Result result) {        if (isCancelled()) {            onCancelled(result); // 如果任務已經被取消了
        } else {            onPostExecute(result); // 通知任務執行完畢
        }
        mStatus = Status.FINISHED;
    }

關于默認執行器 sDefaultExecutor 和線程池

源碼中構建了一個線程池和一個自定義的執行器SerialExecutor??克鼈儊韴绦泻笈_任務。

參考源代碼

public abstract class AsyncTask<Params, Progress, Result> {    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();    // 核心線程至少2個,最多4個
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;    private static final int KEEP_ALIVE_SECONDS = 30;    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;    private static final ThreadFactory sThreadFactory = new ThreadFactory() {        private final AtomicInteger mCount = new AtomicInteger(1);        public Thread newThread(Runnable r) {            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };    private static final BlockingQueue<Runnable> sPoolWorkQueue =            new LinkedBlockingQueue<Runnable>(128);    public static final Executor THREAD_POOL_EXECUTOR; // 實際執行者

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }    // 默認執行器的類
    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);
            }
        }
    }
}

backup at http://rustfisher.github.io/2017/06/22/Android_note/Android-AsyncTask/

http://www.cnblogs.com/rustfisher/p/7220998.html