Handler為什么可以實(shí)現(xiàn)線程間通訊涉馁?

天空灰的他媽的像哭過门岔。

從前經(jīng)常聽到大佬們說,Android是一個(gè)消息驅(qū)動(dòng)型系統(tǒng)烤送,一直都不懂是什么意思寒随。搞了五年Android,還是個(gè)垃圾開發(fā)崽帮坚,問啥啥不會(huì)妻往,再問就CV。每次面試都看一遍Handler试和,看了這么多次讯泣,也是一知半解,總覺得好像會(huì)阅悍,又好像不會(huì)好渠,真的是菜得像狗一樣。事實(shí)證明溉箕,搞IT晦墙,還真是要認(rèn)真動(dòng)腦子的,不動(dòng)腦子肴茄,就會(huì)永遠(yuǎn)停留在會(huì)用的層面上晌畅。最終成為我這樣,一個(gè)CV程序猿寡痰,API程序猿抗楔,垃圾開發(fā)崽。
哎拦坠,好好學(xué)習(xí)下吧连躏。

為什么說Android是一個(gè)消息驅(qū)動(dòng)型系統(tǒng)呢滑废?

最近看了很多Android FrameWork的知識(shí)掠剑,什么AMS,PMS解总,WMS,SystemServer等等勺良。發(fā)現(xiàn)Binder機(jī)制用的最多绰播。比如說,我要啟動(dòng)一個(gè)新的Activity尚困,就要通過Binder配合AMS發(fā)送一個(gè)消息蠢箩,最終配合Handler創(chuàng)建啟動(dòng)這個(gè)Activity。同樣的事甜,啟動(dòng)Service谬泌,發(fā)送廣播。都是這個(gè)大致流程逻谦。
用戶啟動(dòng)Activity消息-------AMS發(fā)送消息給掌实,系統(tǒng)檢查要啟動(dòng)的Activity進(jìn)程是否存在---------檢查完畢發(fā)送Handler消息創(chuàng)建Activity并啟動(dòng)
也就是說,一個(gè)動(dòng)作驅(qū)動(dòng)下一個(gè)動(dòng)作邦马,下一個(gè)動(dòng)作又驅(qū)動(dòng)下下一個(gè)動(dòng)作潮峦,最終返回我們想要的結(jié)果。
這大概就是消息驅(qū)動(dòng)型系統(tǒng)吧勇婴。

FrameWork說多了我也不會(huì)忱嘹,還是搞Handler吧。

首先看一個(gè)Handler初始化的方法

public Handler(@Nullable Callback callback, boolean async) {
        .....
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

可以看到初始化方法里面搞了一個(gè)Looper耕渴,通過Looper又搞了一個(gè)mQueue拘悦。看一下myLooper()方法

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

sThreadLocal是一個(gè)線程存儲(chǔ)數(shù)據(jù)的類橱脸。通過這個(gè)數(shù)據(jù)類獲取到了一個(gè)Looper對(duì)象础米,并返回給了Handler。
由于我們的Handler是在主線程創(chuàng)建的添诉,所以sThreadLocal存儲(chǔ)的是主線程中的looper對(duì)象屁桑。

public static void main(String[] args) {
    ..........
        Looper.prepareMainLooper();
    ..........
         ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

上面這東西就是我們平常所說的主線程,我們的程序都是運(yùn)行在這個(gè)Looper里面栏赴,Looper不停的從MessageQueue中拿出消息蘑斧,處理消息,這也證明了我們Android確實(shí)是消息驅(qū)動(dòng)型系統(tǒng)须眷。
可以看到在main()方法中調(diào)用了Looper的兩個(gè)靜態(tài)方法竖瘾。

 public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
 public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

從這里看到在這里創(chuàng)建了Looper對(duì)象,并且存到了主線程的sThreadLocal中花颗。這樣在前面通過sThreadLocal.get()就得到了一個(gè)主線程的Looper了
Looper.loop()就是從消息隊(duì)列中不停的拿出消息捕传,然后分發(fā)處理。
最后再來看一下Handler發(fā)送消息的過程扩劝。

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

拿到Handler對(duì)應(yīng)的消息隊(duì)列庸论,并將新消息加入到消息隊(duì)列中职辅。
到這里我的分析就完了。

如題聂示,為什么Handler可以實(shí)現(xiàn)線程間通訊呢罐农?

從上面的分析可以看到,當(dāng)我們?cè)谧泳€程中使用handler.sendMessage()的時(shí)候催什,由于這個(gè)子線程中的這個(gè)handler是在主線程創(chuàng)建的,處理這個(gè)消息的Looper宰睡,MessageQueue也都是在主線程中創(chuàng)建的蒲凶。消息一發(fā)送,就立馬把消息發(fā)送到主線程中的這個(gè)MessageQueue中去了拆内,然后被Looper調(diào)用消息旋圆,分發(fā)回調(diào)給我們的主線程handleMessage()方法。也就是說麸恍,這個(gè)消息的發(fā)送處理灵巧,和子線程完全沒有關(guān)系。

其實(shí)抹沪,屌大的大佬們已經(jīng)把Handler的祖宗十八代都分析了好幾遍刻肄。我這個(gè)菜雞分析只是記錄下自己一直迷惑的地方。
想通了這個(gè)問題融欧,再回頭看看Handler敏弃,發(fā)現(xiàn)它也不過如此。我甚至能手寫一個(gè)Handler噪馏,嘿嘿麦到,下篇手寫一下Android系統(tǒng)。哦欠肾,不對(duì)瓶颠,是手寫下Handler。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刺桃,一起剝皮案震驚了整個(gè)濱河市粹淋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瑟慈,老刑警劉巖廓啊,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異封豪,居然都是意外死亡谴轮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門吹埠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來第步,“玉大人疮装,你說我怎么就攤上這事≌扯迹” “怎么了廓推?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長翩隧。 經(jīng)常有香客問我樊展,道長,這世上最難降的妖魔是什么堆生? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任专缠,我火速辦了婚禮,結(jié)果婚禮上淑仆,老公的妹妹穿的比我還像新娘涝婉。我一直安慰自己,他們只是感情好蔗怠,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布墩弯。 她就那樣靜靜地躺著,像睡著了一般寞射。 火紅的嫁衣襯著肌膚如雪渔工。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天桥温,我揣著相機(jī)與錄音涨缚,去河邊找鬼。 笑死策治,一個(gè)胖子當(dāng)著我的面吹牛脓魏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播通惫,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼茂翔,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了履腋?” 一聲冷哼從身側(cè)響起珊燎,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遵湖,沒想到半個(gè)月后悔政,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡延旧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年谋国,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迁沫。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芦瘾,死狀恐怖捌蚊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情近弟,我是刑警寧澤缅糟,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站祷愉,受9級(jí)特大地震影響窗宦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜二鳄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一赴涵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泥从,春花似錦、人聲如沸沪摄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杨拐。三九已至祈餐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哄陶,已是汗流浹背帆阳。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屋吨,地道東北人蜒谤。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像至扰,于是被迫代替她去往敵國和親鳍徽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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