AsyncTask 源碼學習

AsyncTask 是系統提供一種用來執行異步任務的一個工具類,也是我們一直接觸和使用比較多的一個。
只有我們了解了才能好好的使用它,遇到問題才能馬上明白是可能是哪里引起的。

首先有兩個基礎知識:

第一點 AsyncTask如何做到異步線程與主線程通信

代碼版本:api-20

查看源碼發現,實際上他里面是就 Thread + Handler,是不是瞬間感覺這個也不是一個很神秘的東西了。

    //回調主線程
    private Result postResult(Result result) {
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
    //執行了兩個主線程的方法:一個update和一個Result
    private static class InternalHandler extends Handler {
        @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;
            }
        }
    }
        
    @SuppressWarnings({"RawUseOfParameterizedType"})
    private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

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

第二點 AsyncTask的線程是如何調度的

這部分是 AsyncTask 內部線程池創建的方式,一共創建了兩個線程池

  • SERIAL_EXECUTOR 一個線程的線程池
  • SERIAL_EXECUTOR 參見線程池參數
    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);

    //線程池
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

    //執行的線程池
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

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

    private static final InternalHandler sHandler = new InternalHandler();
    //默認執行的線程池
    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);
            }
        }
    }

我們閱讀一下源碼會發現在AsyncTask創建對象的時候會創建兩個對象分別是:mWorkermFuture,這就是前面提到的
Future里面的內容,不明白的需要閱讀一下那篇博客,里面說的很清楚。

然后我們在看一下提交Task地方的代碼:

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        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 = params;
        exec.execute(mFuture);

        return this;
    }

這時候我們會發現AsyncTask把我們提交的任務全部都穿起來一個個執行了,不明白可以看一下SerialExecutor的實現方
法。

每次提交的任務,會有下面情況:

  • 有執行的就把這個任務添加在一個堆棧里面,等待前面任務執行完再執行后面的
  • 沒有任務執行,直接執行當前的任務

所有正常使用AsyncTask來執行一些任務的時候需要特別小心了,不然有個任務執行時間很長后面的任務都沒辦法執行了。
如果不想讓這些人物順序執行可以調用一下這個方法executeOnExecutor,可以指定一個線程池執行。

剩下的就是一些輔助的方法了,例如取消、更新進度等

注:

  • 線程池有個等待隊列數量限制的,如果大于這個數量調用會有異常產生,軟件崩潰,當前隊列最大值是:
    LinkedBlockingQueue<Runnable>(128),這個各個版本有差異的
  • AsyncTask 需要在主線程中創建這個對象,不然Handler的消息也在你創建的那個線程

下面是各個系統下面 AsyncTask 的線程池參數和執行的差異

系統版本 SERIAL_EXECUTOR/THREAD_POOL_EXECUTOR 線程池參數 等待隊列長度
2.2 THREAD_POOL_EXECUTOR 5-128-10 10
2.3 THREAD_POOL_EXECUTOR 5-128-1 10
3.2 THREAD_POOL_EXECUTOR 5-128-1 10
4.0 SERIAL_EXECUTOR 5-128-1 10
4.1 SERIAL_EXECUTOR 5-128-1 10
4.2 SERIAL_EXECUTOR 5-128-1 10
4.3 SERIAL_EXECUTOR 5-128-1 10
4.4 SERIAL_EXECUTOR cpu+-cpux2+1-1 128
5.0 SERIAL_EXECUTOR cpu+-cpux2+1-1 128
6.0 SERIAL_EXECUTOR cpu+-cpux2+1-1 128
N SERIAL_EXECUTOR cpu+-cpux2+1-1 128

謝謝閱讀到這里,覺得好的點個贊吧 _

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

推薦閱讀更多精彩內容