android AsyncTask 源碼分析

使用

AsyncTask的使用不是本文的重點(diǎn),我相信讀者也不是來(lái)了解這個(gè)的,所以就先簡(jiǎn)單的介紹下它的使用,幫助大家回憶。
AsyncTask的實(shí)現(xiàn):

public class DownloadTask extends AsyncTask<Object, Integer, Boolean> {

    /**
     * 在執(zhí)行任務(wù)之前調(diào)用,運(yùn)行在主線程,可用來(lái)做布局更新等
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    /**
     * 執(zhí)行后臺(tái)任務(wù),運(yùn)行在子線程
     */
    @Override
    protected Boolean doInBackground(Object... objects) {
        return false;
    }

    /**
     * 更新進(jìn)度,運(yùn)行在主線程,在doInBackground方法中調(diào)用publishProgress(Integer... values)會(huì)自動(dòng)調(diào)用該方法
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
    }

    /**
     * 后臺(tái)任務(wù)結(jié)束后調(diào)用,運(yùn)行在主線程,參數(shù)aBoolean是doInBackground()方法的返回值
     */
    @Override
    protected void onPostExecute(Boolean aBoolean) {
        super.onPostExecute(aBoolean);
    }

    /**
     * 主動(dòng)調(diào)用cancel()方法,或者doInBackground()方法拋出異常
     */
    @Override
    protected void onCancelled() {
        super.onCancelled();
    }
}

調(diào)用:

    DownloadTask downloadTask = new DownloadTask();
    downloadTask.execute(object1, object2);
    //這里的參數(shù)object1, object2最終會(huì)傳給doInBackground(Object... objects);
源碼思路

先說(shuō)下整體的實(shí)現(xiàn)思路:創(chuàng)建線程池執(zhí)行耗時(shí)任務(wù),通過(guò)handler將進(jìn)度、結(jié)果等送回主線程。

細(xì)節(jié)方面,我們需要研究下,該線程池是怎樣的線程池,它的執(zhí)行邏輯是怎樣的:核心線程數(shù),最大線程數(shù),等待隊(duì)列,拒絕策略等細(xì)節(jié)。順便再了解下上面代碼中的onPreExecute(),onProgressUpdate()等生命周期是在什么時(shí)候執(zhí)行的。

開(kāi)始研究

我們就從我們使用的地方開(kāi)始下手:
DownloadTask downloadTask = new DownloadTask();
downloadTask.execute(object1, object2);

1.下面是其構(gòu)造方法:
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 {
                //設(shè)置標(biāo)志,表示工作任務(wù)開(kāi)始執(zhí)行
                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);
                }
            }
        };
    }

結(jié)構(gòu)很簡(jiǎn)單,一共初始化了三個(gè)全局變量mHandler,mWorker,mFuture。

mHandler,從上面的代碼看,是創(chuàng)建了一個(gè)綁定callbackLooper的handler,所以講道理如果callbackLooper是另一個(gè)子線程的Looper對(duì)象,它也可是實(shí)現(xiàn)兩個(gè)子線程之間的數(shù)據(jù)交互。但是,由于該構(gòu)造方法被@hide隱藏了,我們使用的默認(rèn)無(wú)參構(gòu)造器,最終會(huì)使callbackLooper為null,也就是說(shuō)mHandler賦值為getMainHandler()綁定了主線程。

下面是該handler實(shí)現(xiàn)的handleMessage方法,一個(gè)是處理結(jié)果,一個(gè)是處理進(jìn)度的,這里就先不展開(kāi)細(xì)說(shuō)了,后邊分析到工作線程執(zhí)行到各個(gè)階段時(shí)再細(xì)說(shuō)。

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

mWorker,WorkerRunnable是抽象類(lèi),implements自Callable接口,對(duì)線程池框架比較熟悉的可以知道它將在子線程中調(diào)用執(zhí)行,了解到這點(diǎn)就夠了。

在mWorker實(shí)現(xiàn)的call()方法中最主要的一行代碼doInBackground(mParams);它在這里執(zhí)行了我們的工作任務(wù),然后在catch異常的時(shí)候設(shè)置了標(biāo)志位:mCancelled.set(true),最終在finally中執(zhí)行了postResult()方法。postResult()的邏輯:

private Result postResult(Result result) {
        //getHandler()會(huì)返回mHandler,也就是上面介紹的綁定了主線程Looper對(duì)象的Handler
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

這就和我們上面講到的handleMessage對(duì)Message的處理聯(lián)系了起來(lái),最終會(huì)執(zhí)行finish()方法,并在這里調(diào)用我們實(shí)現(xiàn)的onCancelled()或者onPostExecute()生命周期:

private void finish(Result result) {
        //isCancelled()方法會(huì)判斷是否是取消導(dǎo)致,
        //比如上面說(shuō)的執(zhí)行mWorker.call()時(shí)catch異常和我們做活動(dòng)調(diào)用AsyncTask的cancel()方法會(huì)使isCancelled()返回ture
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

WorkerRunnable除了implements Callable接口還添加了個(gè)mParams數(shù)組,也就是doInBackground(mParams),執(zhí)行時(shí)會(huì)傳入的參數(shù)

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
}

mFuture FutureTask本篇不做深入的了解,它的目的是獲取子線程運(yùn)算結(jié)果和提供子線程的中斷方法。上面代碼對(duì)于mFuture的初始化可以看到它將mWorker封裝在了內(nèi)部,所以以后的操作對(duì)象都變?yōu)榱薽Future。mWork只是提供了call()方法(Callable接口)和參數(shù)mParams。

2.execute:

構(gòu)造方法就是初始化了三個(gè)變量,mHandler,mWorker,mFuture。接下來(lái)我們看下execute()執(zhí)行了哪些步奏:downloadTask.execute(object1, object2);

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        //內(nèi)部調(diào)用了executeOnExecutor方法
        return executeOnExecutor(sDefaultExecutor, 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變量賦值
        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

可以看到execute()就是調(diào)用了executeOnExecutor()方法。executeOnExecutor()的前部分就是判斷了當(dāng)前AsyncTask的狀態(tài)只有在Status.PENDING的狀態(tài)才可以正常運(yùn)行,并且在運(yùn)行后立即將狀態(tài)改為了Status.RUNNING,也就是說(shuō)同一個(gè)AsyncTask對(duì)象只能execute()一次。

接著就是調(diào)用了onPreExecute();也就是我們執(zhí)行任務(wù)前在主線程做一些初始化的操作,比如加載界面。

最后最重要的工作exec.execute(mFuture)來(lái)執(zhí)行我們的工作任務(wù)。毋庸置疑,該方法最終會(huì)執(zhí)行到mWorker的call()方法。我們現(xiàn)在要研究的就是這個(gè)Executor對(duì)象(即調(diào)用executeOnExecutor()時(shí)傳入的sDefaultExecutor),它是怎樣的線程池,我們傳入的FutureTask對(duì)象將被如何調(diào)用。

sDefaultExecutor

終于我們要開(kāi)始研究AsyncTask的核心內(nèi)容了sDefaultExecutor(其實(shí)不是)。為什么說(shuō)不是呢,因?yàn)閟DefaultExecutor只是一個(gè)任務(wù)安排者,并不真正的創(chuàng)建線程執(zhí)行任務(wù)??聪聅DefaultExecutor的源碼:

    /**
    *sDefaultExecutor最終會(huì)指向SerialExecutor對(duì)象
    **/
    private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
        //SerialExecutor并沒(méi)有任何地方創(chuàng)建線程,execute也只是將任務(wù)放進(jìn)ArrayDeque隊(duì)列中
        //之前我們傳入的是FutureTask對(duì)象,而這里需要的參數(shù)是Runnable對(duì)象是因?yàn)椋?   
        //FutureTask也實(shí)現(xiàn)了Runnable接口,并將Callable接口(即mWorker)的call()方法在run()方法中調(diào)用
        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才是最終執(zhí)行任務(wù)的線程池
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

ok,我們先看下它是怎樣安排任務(wù)的。1.將任務(wù)runnable稍作包裝提交到mTasks中并插入到隊(duì)列尾部。2.判斷mActive是否為null,如果不為null則執(zhí)行scheduleNext()。

第一次運(yùn)行AsyncTask時(shí)肯定為null,所以會(huì)立即執(zhí)行scheduleNext(),可以看到mTasks.poll()會(huì)從隊(duì)列首部取出任務(wù)賦值給mActive,并且通過(guò)真正的線程池THREAD_POOL_EXECUTOR去執(zhí)行。

當(dāng)任務(wù)完成后會(huì)在finally中調(diào)用scheduleNext()方法去查看mTasks隊(duì)列中是否有剩余任務(wù),如果有則安排,沒(méi)有則mActive置為null。保證下次創(chuàng)建新的AsyncTask時(shí),mActive為正確值(因?yàn)閟DefaultExecutor為static變量,全局只有一個(gè)sDefaultExecutor對(duì)象),這也表示如果短時(shí)間內(nèi)創(chuàng)建多個(gè)AsyncTask,并且每個(gè)AsyncTask執(zhí)行時(shí)間還比較長(zhǎng),那后執(zhí)行AsyncTask.execute()方法的任務(wù)將需要等待前面的任務(wù)執(zhí)行完成才能開(kāi)始。也就是說(shuō)AsyncTask其實(shí)是串行執(zhí)行的。
若想并行執(zhí)行也是有方法的,直接調(diào)用executeOnExecutor(THREAD_POOL_EXECUTOR, params);跳過(guò)sDefaultExecutor的代理。

THREAD_POOL_EXECUTOR

終于到了研究線程池的這一步了

/**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(), sThreadFactory);
        threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

核心線程數(shù):CORE_POOL_SIZE = 1,最大線程數(shù):MAXIMUM_POOL_SIZE = 20,空閑線程持續(xù)時(shí)間KEEP_ALIVE_SECONDS = 3(秒),SynchronousQueue這是等待隊(duì)列,線程工廠: sThreadFactory,最后設(shè)置了拒絕策略sRunOnSerialPolicy。
SynchronousQueue沒(méi)有容量,是無(wú)緩沖等待隊(duì)列,是一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列。也就是說(shuō)最多同時(shí)執(zhí)行20個(gè)線程任務(wù)。再有新的任務(wù)則會(huì)執(zhí)行拒絕策略sRunOnSerialPolicy,我們看下sRunOnSerialPolicy的源碼:

    private static final int BACKUP_POOL_SIZE = 5;
    private static final RejectedExecutionHandler sRunOnSerialPolicy =
            new RejectedExecutionHandler() {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            android.util.Log.w(LOG_TAG, "Exceeded ThreadPoolExecutor pool size");
            // As a last ditch fallback, run it on an executor with an unbounded queue.
            // Create this executor lazily, hopefully almost never.
            synchronized (this) {
                if (sBackupExecutor == null) {
                    sBackupExecutorQueue = new LinkedBlockingQueue<Runnable>();
                    sBackupExecutor = new ThreadPoolExecutor(
                            BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,
                            TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory);
                    sBackupExecutor.allowCoreThreadTimeOut(true);
                }
            }
            sBackupExecutor.execute(r);
        }
    };

很簡(jiǎn)單,又創(chuàng)建了個(gè)備用線程池,只有BACKUP_POOL_SIZE個(gè)核心線程(5個(gè)),然后核心線程也會(huì)超時(shí),畢竟備用線程池,邏輯上來(lái)講需要也不需要長(zhǎng)時(shí)間保留。sBackupExecutorQueue的容量是Integer.Max,所以說(shuō)若短時(shí)間執(zhí)行大量任務(wù),則會(huì)將后續(xù)的任務(wù)都添加在sBackupExecutorQueue中,然后等待備用線程的調(diào)用,這時(shí)候,主線程池的即使結(jié)束了任務(wù),也不會(huì)去執(zhí)行新的任務(wù),sBackupExecutorQueue中的任務(wù)將由備用線程池的5個(gè)線程去執(zhí)行。這點(diǎn)上沒(méi)有注意到可能會(huì)影響AsyncTask的使用效率:

如下圖每隔3秒,子線程的任務(wù)完成后,只會(huì)有5個(gè)新的任務(wù)執(zhí)行(log中的starttask)
image.png

總結(jié):

整體來(lái)說(shuō)AsyncTask思路很簡(jiǎn)單,就是創(chuàng)建線程池,在子線程執(zhí)行任務(wù)前調(diào)用onPreExecute(),在子線程中調(diào)用doInBackground(),然后執(zhí)行過(guò)程中調(diào)用publishProgress()通過(guò)handler發(fā)送進(jìn)度到主線程執(zhí)行onProgressUpdate(),最后執(zhí)行完成后再通過(guò)handler發(fā)送Result到主線程執(zhí)行onPostExecute()或者onCancelled()
需要多注意的就是對(duì)于線程池要有一定的了解,否則讀起源碼來(lái)將有些困難。

?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 在Android中ui是非線程安全的,更新ui只能在主線程操作,所以我們平時(shí)如果遇到子線程更新UI的情況,必須要切...
    寒小楓閱讀 413評(píng)論 0 1
  • 1. 基本用法 第一個(gè) 對(duì)應(yīng)doInBackground 指定需要傳入的參數(shù), 第二個(gè) 對(duì)應(yīng)onProgres...
    天道__閱讀 259評(píng)論 0 0
  • 闖關(guān)關(guān)卡---第9關(guān),闖關(guān)進(jìn)度20%,繼續(xù)打怪升級(jí) 一直以來(lái)都沒(méi)有使用過(guò)AsyncTask,且因?yàn)橛蠷xjava的...
    Czppp閱讀 286評(píng)論 0 0
  • 一、核心思想 AsyncTask 提供一個(gè)根據(jù)CPU核心數(shù)來(lái)確定的一個(gè)線程池,任務(wù)通過(guò)FutureTask提交給線...
    xyooyy閱讀 163評(píng)論 0 0
  • 標(biāo)簽:Android AsyncTask 源碼解析 1.關(guān)于AsyncTask 1.1 什么是AsyncTask?...
    koguma閱讀 667評(píng)論 0 2

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