深入解析AsyncTask的原理

博文出處:深入解析AsyncTask的原理,歡迎大家關(guān)注我的博客,謝謝!

前言

在初學(xué) Android 的時候,AsyncTask 應(yīng)該是大家都比較熟悉的。我們都知道 AsyncTask 可以在后臺開啟一個異步的任務(wù),當(dāng)任務(wù)完成后可以更新在 UI 上。而在 AsyncTask 中,比較常用的方法有: onPreExecute 、 doInBackground 、 onPostExecute 和 onProgressUpdate 等。而上述的方法中除了 doInBackground 運行在子線程中,其他的都是運行在主線程的,相信大家對這幾個方法也了如指掌了。

在這里先劇透一下, AsnycTask 原理就是“線程池 + Handler”的組合。如果你對Handler消息傳遞的機制不清楚,那么可以查看我上一篇的博文:《探究Android異步消息的處理之Handler詳解》,里面會有詳細的介紹。那么接下來,就一起來看看 AsyncTask 實現(xiàn)的原理吧!

class

public abstract class AsyncTask<Params, Progress, Result> {
    ...
}

AsyncTask 為抽象類,其中有三個泛型。這三個泛型相信大家都很熟悉了,第一個是傳遞的參數(shù)類型,第二個是任務(wù)執(zhí)行的進度,第三個是任務(wù)執(zhí)行的結(jié)果類型了。如果其中某個不需要可以傳入Void。

線程池

那么我們先來看看 AsyncTask 里的線程池:

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;

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

/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 */
public static final Executor THREAD_POOL_EXECUTOR
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

從上面我們可以看到,該線程池(即 THREAD_POOL_EXECUTOR)的核心線程數(shù)為 CPU 的核心數(shù)量 + 1,最大線程數(shù)為 CPU 的核心數(shù)量 * 2 + 1,過剩線程的存活時間為1s。這里要注意的是 sPoolWorkQueue 是靜態(tài)阻塞式的隊列,意味著所有的 AsyncTask 用的都是同一個 sPoolWorkQueue ,也就是說最大的容量為128個任務(wù),若超過了會拋出異常。最后一個參數(shù)就是線程工廠了,用來制造線程。

我們再來看看 AsyncTask 內(nèi)部的任務(wù)執(zhí)行器 SERIAL_EXECUTOR ,該執(zhí)行器用來把任務(wù)傳遞給上面的 THREAD_POOL_EXECUTOR 線程池。在 AsyncTask 的設(shè)計中,SERIAL_EXECUTOR 是默認的任務(wù)執(zhí)行器,并且是串行的,也就導(dǎo)致了在 AsyncTask 中任務(wù)都是串行地執(zhí)行。當(dāng)然,AsyncTask 也是支持任務(wù)并行執(zhí)行的,這個點我們在下面再講。

/**
 * An {@link Executor} that executes tasks one at a time in serial
 * order.  This serialization is global to a particular process.
 */
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();
                } finally {
                    scheduleNext();
                }
            }
        });
        if (mActive == null) {
            scheduleNext();
        }
    }

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

可以從 SerialExecutor 的內(nèi)部看到,是循環(huán)地取出 mActive ,并且把 mActive 放置到上面的 THREAD_POOL_EXECUTOR 中去執(zhí)行。這樣就導(dǎo)致了任務(wù)是串行地執(zhí)行的。

Handler

講完了線程池,那么剩下的就是 Handler 了。下面是 AsyncTask 內(nèi)部實現(xiàn)的一個 Handler :

private static InternalHandler sHandler;

private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;

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

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

@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
    final AsyncTask mTask;
    final Data[] mData;

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

在源碼中,有一個靜態(tài)的 sHandler ,還有定義了兩條消息的類型。一條表示傳送結(jié)果,另一條表示傳送進度。再來分析一下 InternalHandler 的源碼:在 InternalHandler 的 handleMessage 方法中,根據(jù)消息類型分別有不同的處理。其中的 result.mTask 可以從 AsyncTaskResult 類中看到,就是 AsyncTask 本身。而后邊的方法有一些眼熟啊。其中 finish 應(yīng)該是在任務(wù)結(jié)束時回調(diào)的,若任務(wù)完成會回調(diào) onPostExecute 方法,否則會回調(diào) onCancelled 方法;而消息類型為 MESSAGE_POST_PROGRESS 中的 onProgressUpdate 方法不就是我們在使用 AsyncTask 時重寫的那個方法么。在這里我們已經(jīng)可以看出點端倪了。但是我們先賣個關(guān)子,繼續(xù)向下看。

構(gòu)造器

再來看看 AsyncTask 的構(gòu)造器:

private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
    
/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 */
public AsyncTask() {
    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);
            }
        }
    };
}

@WorkerThread
protected abstract Result doInBackground(Params... params);

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

private void postResultIfNotInvoked(Result result) {
    final boolean wasTaskInvoked = mTaskInvoked.get();
    if (!wasTaskInvoked) {
        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;
}

private static Handler getHandler() {
    synchronized (AsyncTask.class) {
        if (sHandler == null) {
            sHandler = new InternalHandler();
        }
        return sHandler;
    }
}

在構(gòu)造器中創(chuàng)建了 WorkerRunnable 和 FutureTask 的對象,而在 WorkerRunnable 內(nèi)部的 call 方法中會去執(zhí)行需要我們重寫的 doInBackground 方法。而如果在 doInBackground 方法中調(diào)用 publishProgress 方法,就會使用發(fā)送消息到 sHandler 的 handleMessage 方法,之后就調(diào)用了 onProgressUpdate 方法了,具體可見上面的 InternalHandler 中的代碼。最后如果任務(wù)結(jié)束了在 postResult 中發(fā)送消息給 sHandler ,就是要在 handleMessage 中拿到消息并且執(zhí)行上面分析過的 finish 方法了。

execute

最后我們來講講 execute 方法,以下是源碼:

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

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

@MainThread
protected void onPreExecute() {
}

在上面中可以看到我們平常使用的 execute 方法會去調(diào)用 executeOnExecutor 方法。而在 executeOnExecutor 方法內(nèi)又會去調(diào)用 onPreExecute 方法。這也就是為什么 onPreExecute 方法是在任務(wù)開始運行之前調(diào)用的原因了。這里要注意的是,如果想讓 AsyncTask 并行地去執(zhí)行任務(wù),那么可以在 executeOnExecutor 方法中傳入一個并行的任務(wù)執(zhí)行器,這樣就達到了并行的效果。

總結(jié)

好了,AsyncTask 的源碼大致就這些了,也分析地差不多了。我們總共分成了 class 、線程池、Handler 、構(gòu)造器和 execute 五部分來分析。這樣可能會給人比較散亂的感覺,但是連起來看就會對 AsyncTask 的原理更加了解了。那么,下面我們就來總結(jié)一下吧:

  • AsyncTask 的線程池的線程數(shù)量是和 CPU 的核心數(shù)相關(guān)的。而線程池的隊列是阻塞式的并且是有限的,最大容量為128。這也意味著 AsyncTask 不適合于做一些大型的、長期在后臺運行的任務(wù)。因為這樣可能導(dǎo)致著隊列的溢出,會拋出異常。所以 AsyncTask 適合于一些小型的任務(wù)。

  • onProgressUpdate、 onCancelled 和 onPostExecute 等都是通過 handler 的消息傳遞機制來調(diào)用的。所以 AsyncTask 可以理解為“線程池 + Handler”的組合。

  • 在 execute 方法中,會先去調(diào)用 onPreExecute 方法,之后再在線程池中執(zhí)行 mFuture 。這時會調(diào)用 doInBackground 方法開始進行任務(wù)操作。 mWorker 和 mFuture 都是在構(gòu)造器中初始化完成的。

  • AsyncTask 支持多線程進行任務(wù)操作,默認為單線程進行任務(wù)操作。

今天就到這里了,下次再見!

Goodbye ~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容