多線程(四)AsyncTask原理

最近聽了很多情感生活方面的書,最近也在知乎上看到了很多關於渣男,舔狗的評論。觀點不盡相同,有抨擊的有點讚的。
個人覺得,渣男我就不評論了,那種喜歡欣賞多個小姐姐的我贊同,但是你有女朋友的時候,請你做到男朋友應有的責任,如果更喜歡另一個,就分手在去追第二個你更喜歡的。如果你真的愛你的女朋友就不會更喜歡另一個,也就是你所謂更喜歡的第二個。
舔狗,一往情深的就不多說了,祝你遇上對的人。沒有尊嚴和底線的去舔就醒醒好嗎?女孩子不是追的(是去征服她去吸引她),不然你會一直處於段位低的那個人。就算最後你感動到了她,她也同意和你在一起,但是往往這種戀愛沒有你們想的那麼偶像劇,這是一種病態的戀愛。雙方段位的不對等,你的生活需要很多的磨合,如果真的是這樣,朋友請你加油,提升自己。


目錄
  1. AsyncTask的使用
  2. AsyncTask的原理
  3. 總結
1. AsyncTask的使用

使用教程算是比較詳細的了AsyncTask的使用

2. AsyncTask的原理

一講到原理,大家都知道需要看源碼,這時候就要用到最常用的源碼查看工具
Source Insight 4.0了
我以Android8.0的源碼爲例子講解AsyncTask源碼
我們先看看它的構造方法

public AsyncTask() {
	mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
	    ? getMainHandler()
	    : new Handler(callbackLooper);
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
			// 設置線程的優先級
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            // 把異步操作執行的結果發送到主線程
            return postResult(doInBackground(mParams));
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
            try {
            	// 在執行完任務後檢查,將沒被調用的Result也一併發出
                postResultIfNotInvoked(get());
            } catch (InterruptedException e) {
                android.util.Log.w(LOG_TAG, e);
            } catch (ExecutionException e) {
                throw new RuntimeException("An error occured while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
            	//若 發生異常,則將發出null
                postResultIfNotInvoked(null);
            }
        }
    };
}

我們在看看在activity中它的execute方法的調用的源碼

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

進入到我們的下一步executeOnExecutor方法中

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;//1
    exec.execute(mFuture);

    return this;
}

從註釋1我們可以看出將AsyncTask的參數傳給了WorkerRunnable,從前面的構造方法中我們知道WorkerRunnable是作爲參數傳給了FutureTask。exec是傳進來的參數是sDefaultExecute它是一個串行的線程池SerialExecutor
我們在看看下面的exec.exectue方法
在這裏插入圖片描述
在看看我們的sDefaultExecutor.execute(runnable);方法

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() {//0
            public void run() {
                try {
                    r.run();//1
                } finally {
                    scheduleNext();//2
                }
            }
        });
        if (mActive == null) {
            scheduleNext();
        }
    }

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

在這一段代碼的註釋0中會將FutureTask加入到mTasks中,不管有沒有執行完成或者當前活動沒有在finally中都會執行scheduleNext方法,從這個方法取出FutureTask任務並交由THREAD_POOL_EXECUTOR處理。這個後面在談
我們在註釋1看到了FutureTask的run方法回到構造方法中我們可以看到它最終會調用WorekerRunnable的call方法,前面我們看到這個call最終是被return result的,我們看看這個postResult(result)方法的代碼
在這裏插入圖片描述
創建message,嘿嘿好的,我們先從handler開始看,再看看我們的getHandler方法
在這裏插入圖片描述
這個方法簡單
看看我們的構造方法對mHandler做了什麼。
在這裏插入圖片描述
在看看我們的getMainHandler方法
在這裏插入圖片描述
什麼意思呢就是mHandler 在callbackLooper==null的時候和不在主線程的時候就給它創建一個在主線程的InternalHandler(Looper.getMainLooper()),我們在看看InternalHandler類的定義
在這裏插入圖片描述
直接看到switch 在接收到MESSAGE_POST_RESULT消息後調用AsyncTask的finish方法下面那個進度你懂的,我們看看finish方法代碼
在這裏插入圖片描述
到了這一步是不是就很明朗了。如果AsyncTask任務取消了,則執行onCancelled方法
否則調用onPoastExecute方法。我們就能得到異步任務執行後的結果。


我們回過頭來在看看SerialExecutor
在這裏插入圖片描述
是這樣一個線程池,THREAD_POOL_EXECUTOR指的是threadPoolExecutor,其核心線程和線程池允許創建的最大線程數都是由cpu的核數來計算出來的,他的組賽隊列是LinkedBlockingQueue容量是128
在Android3.0之前AsyncTask是並行運行的,在3.0之後是串行,它保證了一個時間段只有一個任務執行,因爲線程一個一個執行不會出現超過任務數和執行飽和策略的情況,同時也是提醒我們在使用多線程和阻塞隊列的時候要注意任務的數量。合理編碼提高我們的代碼質量。
當然在3.0之後也可以並行的線程處理。
可以調用executeOnExecutor方法傳遞AsyncTask.THREAD_POOL_EXECUTOR參數
當然除了並行也可以傳遞我們的四種線程池和自定義線程池。


3. 總結

AsyncTask的原理講完了,多線程也講完了,之前可能大家覺得這個多線程好像和我們Android開發關係不大,但是這次的源碼講解是不是讓你有了一定的瞭解,多線程真的無處不在,從我們的AsyncTask源碼到線程池到阻塞隊列,到線程。你會發現這些其實不是特別難,好了祝你在學習的過程中,輕鬆又快樂。
點擊關注,下次我會講解網絡編程和網絡框架,下下次講一下我們的設計模式。
奇淫巧計,爲求一讚。
下面抄了我大哥的幾行代碼,娛樂一下。

/**
 *   ------------------------------------
 *     中國 Android 編程第三區交通委提醒您:
 *   ------------------------------------
 *
 *     風 格 千 萬 種
 *     規 範 第 一 條
 *     代 碼 無 注 釋
 *     同 事 兩 行 淚
 *
 *     注 釋 千 萬 種
 *     編 程 第 一 條
 *     盡 量 自 解 釋
 *     刪 除 無 用 功
 *
 *   -----------------------------------------------------------
 *     中國 Android 編程交通委提醒您,飆車請遵守交通規則,注意安全!
 *   -----------------------------------------------------------
 *
 *  Created by syt on 2019/04/22.
 */
/***
 * ░░░░░░░░░░░░░░░░░░░░░░░░▄░░
 * ░░░░░░░░░▐█░░░░░░░░░░░▄▀▒▌░
 * ░░░░░░░░▐▀▒█░░░░░░░░▄▀▒▒▒▐
 * ░░░░░░░▐▄▀▒▒▀▀▀▀▄▄▄▀▒▒▒▒▒▐
 * ░░░░░▄▄▀▒░▒▒▒▒▒▒▒▒▒█▒▒▄█▒▐
 * ░░░▄▀▒▒▒░░░▒▒▒░░░▒▒▒▀██▀▒▌
 * ░░▐▒▒▒▄▄▒▒▒▒░░░▒▒▒▒▒▒▒▀▄▒▒
 * ░░▌░░▌█▀▒▒▒▒▒▄▀█▄▒▒▒▒▒▒▒█▒▐
 * ░▐░░░▒▒▒▒▒▒▒▒▌██▀▒▒░░░▒▒▒▀▄
 * ░▌░▒▄██▄▒▒▒▒▒▒▒▒▒░░░░░░▒▒▒▒
 * ▀▒▀▐▄█▄█▌▄░▀▒▒░░░░░░░░░░▒▒▒
 * 單身狗就這樣默默地看着你,一句話也不說。
 */
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章