AsyncTask機(jī)制詳解

先把AsyncTask的基本用法熟悉一遍

   class MyAsyncTask extends AsyncTask<Void, Integer, String> {
    @Override
    protected void onPreExecute() {
        //準(zhǔn)備一些初始化操作
    }

    @Override
    protected String doInBackground(Void... params) {
      //后臺操作
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
       //更新進(jìn)度
    }

    @Override
    protected void onPostExecute(String s) {
      //得到后臺操作返回的結(jié)果
    }
}

new MyAsyncTask().execute();  

Void,Integer,String三個(gè)類型分別是在做后臺操作時(shí)傳入的參數(shù), 更新的進(jìn)度, doInBackground操作里返回的結(jié)果陈醒。

上面就是基本的用法,接下來進(jìn)入正題分析AsyncTask的源碼.
首先我們new了一個(gè)MyAsyncTask的實(shí)例借跪。那么AsyncTask的源碼里做了什么呢产雹?

  public AsyncTask() {
    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 {
                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) {
                postResultIfNotInvoked(null);
            }
        }
    };
}

可以看出是實(shí)例化了一個(gè)WorkerRunnable對象,一個(gè)FutureTask對象锻霎。我們先不管這2個(gè)對象有什么用。細(xì)心的同學(xué)可以發(fā)現(xiàn)call()這里調(diào)用了doInBackground方法。這里的疑問我們先放下。
然后看我們new完一個(gè)MyAsyncTask后我們執(zhí)行了execute()方法瓤狐。我們到源碼了看execute()執(zhí)行了什么瞬铸。

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

就一段代碼,
我們看到底 executeOnExecutor方法里到底執(zhí)行了什么础锐。

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

看到這里我們有點(diǎn)眉目了嗓节,onPreExecute()方法露面了,確實(shí)是onPreExecute()最先執(zhí)行皆警。
然后我們看到 exec.execute(mFuture)這段代碼拦宣。這里顯然可以看出sDefaultExecutor執(zhí)行了execute方法。繼續(xù)努力信姓,找出sDefaultExecutor的execute方法鸵隧。我們發(fā)現(xiàn)這個(gè)sDefaultExecutor其實(shí)就是實(shí)現(xiàn)了Executo的execute接口。

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

r.run()的r就是上面的mFuture意推。還記得我在文章開頭說的WorkerRunnable對象豆瘫,F(xiàn)utureTask對象嗎?在創(chuàng)建AsyncTask的時(shí)候就已經(jīng)實(shí)例化了mFuture菊值。所以這里
其實(shí)就是執(zhí)行了mFuture的run方法外驱。那么問題來了,在哪里能看出run方法里做了什么鬼東西呢?首先我們可以看出mFuture是一個(gè)FutureTask對象,我們來看看他的構(gòu)造函數(shù)

 public
 FutureTask(Callable<V> callable) {

}

在實(shí)例化的時(shí)候

mFuture = new FutureTask<Result>(mWorker)

而WorkerRunnable又實(shí)現(xiàn)了Callable這個(gè)接口.
講到這里大家或許已經(jīng)明白了,run方法里執(zhí)行的是mWorker里的call() 方法腻窒。

而在call() 方法里有這樣的一段代碼

return postResult(doInBackground(mParams));

哈哈,doInBackground出現(xiàn)了昵宇。這里的mParams就是我們傳入的參數(shù),并且返回了postResult的返回值。那postResult又是什么呢儿子?

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

沒錯(cuò)你沒有看錯(cuò),其實(shí)AsyncTask內(nèi)部也是通過Handler來進(jìn)行線程間通信的瓦哎。在這里我們可以看到在doInBackground返回結(jié)果后postResult通過Handler發(fā)送了一個(gè)MESSAGE_POST_RESULT消息。getHandler()返回的就是這個(gè)InternalHandler柔逼。

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

然后我們看在處理MESSAGE_POST_RESULT消息時(shí)做了這樣的一件事情

   result.mTask.finish(result.mData[0]);

繼續(xù)看源碼

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

哈哈豁然開朗啊, 出現(xiàn)了 onPostExecute,可以看到在這里把doInBackground的返回值給了onPostExecute蒋譬。然后把狀態(tài)設(shè)置為 Status.FINISHED

講到這里基本的流程都已經(jīng)講完了,但是我想糾正網(wǎng)上大多是的帖子關(guān)于這個(gè)AsyncTask其實(shí)就是Thread和Handler的結(jié)合的說法。更準(zhǔn)確的說法是FutureTask和Handler的結(jié)合卒落。為什么羡铲?
因?yàn)門hread的run方法返回值是void。而我們看AsyncTask的源碼里的call() 方法里是返回了后臺操作結(jié)果,我們再看儡毕,源碼里有這樣的一個(gè)方法

postResultIfNotInvoked(get());

而這個(gè)get()我們看

 public final Result get() throws InterruptedException, ExecutionException {
    return mFuture.get();
}

其實(shí)就是返回了FutureTask的執(zhí)行結(jié)果,也就是call()方法返回結(jié)果也切。

因此用Thread是達(dá)不到這種要求的。

基本流程大概就是這樣腰湾。謝謝各位看官雷恃,歡迎拍磚!7逊弧倒槐!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市附井,隨后出現(xiàn)的幾起案子讨越,更是在濱河造成了極大的恐慌两残,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件把跨,死亡現(xiàn)場離奇詭異人弓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)着逐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門崔赌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人耸别,你說我怎么就攤上這事健芭。” “怎么了秀姐?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵慈迈,是天一觀的道長。 經(jīng)常有香客問我囊扳,道長吩翻,這世上最難降的妖魔是什么兜看? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任锥咸,我火速辦了婚禮,結(jié)果婚禮上细移,老公的妹妹穿的比我還像新娘搏予。我一直安慰自己,他們只是感情好弧轧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布雪侥。 她就那樣靜靜地躺著,像睡著了一般精绎。 火紅的嫁衣襯著肌膚如雪速缨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天代乃,我揣著相機(jī)與錄音旬牲,去河邊找鬼。 笑死搁吓,一個(gè)胖子當(dāng)著我的面吹牛原茅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播堕仔,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼擂橘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了摩骨?” 一聲冷哼從身側(cè)響起通贞,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤朗若,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后昌罩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捡偏,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年银伟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绘搞。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖夯辖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蒿褂,我是刑警寧澤圆米,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布啄栓,位于F島的核電站,受9級特大地震影響昙楚,放射性物質(zhì)發(fā)生泄漏近速。R本人自食惡果不足惜堪旧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淳梦。 院中可真熱鬧,春花似錦爆袍、人聲如沸首繁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至谆扎,卻和暖如春挂捅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背堂湖。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工闲先, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留状土,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓伺糠,卻偏偏與公主長得像蒙谓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子训桶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355

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