Android-Handler消息處理機制

Handler:誰發(fā)送愧驱,誰處理狠鸳,主要工作就是消息的發(fā)送和接收過程夺饲。消息的發(fā)送可以通過post的一系列方法以及send的一系列方法來實現(xiàn)装盯,post的方式最終是通過send的方法來實現(xiàn)的废睦。
Handler發(fā)送一條消息的過程

public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg,0);
}
public final boolean sendMessageDelayed(Message msg,long delayMillis){
      if(delayMillis<0){
              delayedMillis=0;
      }
      return sendMessageAtTime(msg,SystemColock.uptimeMillis()+delayMillis);
}
public boolean sendMessageAtTime(Message msg,long uptimeMillis){
        MessageQueue queue=mQueue;
        if(queue==null){
               RuntimeExection e=new RuntimeException(this+"sendMessageAtTime() called with no mQuene")
                Log.w("looper",e.getMessage(),e);
                return false;
         }
           //向隊列中插入一條消息
          return enqueueMessage(queue,msg,uptimeMillis);
 }
private boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMillis){
        msg.target=this;
        if(mAsynchronous){
              msg.setAsychronous(true);
        } 
        return queue.enqueueMessage(msg,uptimeMillis);
}

Handler發(fā)送消息的過程是向消息隊列中插入一條消息伺绽,MessageQueue的next方法就會返回這條消息給Looper,Looper收到這條消息之后就開始處理了嗜湃,最終消息由looper交由Handler處理奈应,即Handler的dispatchmessage方法會被調(diào)用,這是Handler就進入處理消息的階段购披。

public void dispatchMessage(Message msg){
          //檢查message的callback是否為null
          if(msg.calllback!=null){
              handleCallback(msg);           
           }
            else{
                  if(mCallback!=null){
                            if(mCallback.handleMessage(mssg)){
                                    return;
                              } 
                   }
                    handleMessage(msg);
             }
}

Handlet處理消息的過程
首先杖挣,檢查Message的callback是否為null,不為空就通過handleCallback來處理消息。message的callback是一個Runnbale對象刚陡,實際上就是Handler的post方法所傳遞的Runnable參數(shù)惩妇。

private static void handleCallback(Message message){
        message.callback.run(); 
}

其次,檢查mCallback是否為空筐乳,不為null及調(diào)用mCallback的handleMessage方法來處理消息

public interface Callback{
      public boolean handleMessage(Message msg); 
}


從這個圖中我們很清楚可以看到調(diào)用sendEmptyMessage后歌殃,會把Message對象放入一個MessageQueue隊列,該隊列屬于某個Looper對象蝙云,每個Looper對象通過ThreadLocal.set(new Looper())跟一個Thread綁定了氓皱,Looper對象所屬的線程在Looper.Loop方法中循環(huán)執(zhí)行從MessageQueue隊列讀取Message對象,并把Message對象交由Handler處理勃刨,調(diào)用Handler的dispatchMessage方法波材。
現(xiàn)在我們再來看一下使用Handler的基本實現(xiàn)代碼:

       // 主線程中新建一個handler
         Handler  h= new Handler() {
                  public void handleMessage(android.os.Message msg) {             
                    }
            };

Android的消息機制主要是Handler的運行機制,Handler的運行需要底層MessageQueue和looper的支撐身隐。
MessageQueue:消息隊列廷区,內(nèi)部存儲了 一組消息,以隊列的形式提供插入和刪除的工作抡医。
Looper:消息循環(huán)躲因,由于MessageQueue只是一個消息的存儲單元 ,他不能去處理消息忌傻,Looper就填補了這個功能大脉,Looper會以無限循環(huán)的形式去找是否有這個消息,如果有消息的話就處理消息水孩,否則就一直等待镰矿。線程是默認沒有Looper的,如果需要使用Handler及必須為線程創(chuàng)建Looper俘种。

在一個Android程序中開始運行的時候秤标,會單獨開啟一個進程绝淡。默認的情況下所有這個程序中(四大組件)Activity,Service,Content Provider ,Broadcase Receiver 都會跑在這個進程中苍姜。一個Android程序默認情況下也只有一個進程牢酵,但一個進程卻可以有多個線程(Thread)。在這么多Thread當中衙猪,有一個Thread,我們稱之為UI Thread.UI Thread在Android程序運行的時候就被創(chuàng)建馍乙,是一個Process當中的主線程Main Thread,主要是負責控制UI界面的顯示垫释、更新和控件交互丝格。在Android程序創(chuàng)建之初,一個Process呈現(xiàn)的是單線程模型棵譬,所有的任務都在一個線程中運行显蝌。因此,我們認為订咸,UI Thread所執(zhí)行的每一個函數(shù)曼尊,所花費的時間都應該是越短越好。而其他比較費時的工作(訪問網(wǎng)絡算谈,下載數(shù)據(jù)涩禀,查詢數(shù)據(jù)庫等),都應該交由子線程去執(zhí)行然眼,以免阻塞主線程艾船,導致ANR。那么問題來了高每,UI 主線程和子線程是怎么通信的呢屿岂。這就要提到我們這里要講的Handler機制。

Handler機制被引入的目的就是為了實現(xiàn)線程間通信鲸匿。Handler一共干了兩件事:在子線程中發(fā)出massage,在主線程獲取爷怀,處理message。聽起來好像很容易带欢,如果面試中讓你闡述下Handler機制运授,我們這么回答顯然不是面試官想要的答案。我們忽略了一個問題:子線程何時發(fā)送message,主線程何時獲取處理message乔煞。

在這張圖我們可以看到首先在ActivityThread創(chuàng)建UI線程吁朦,然后會看到有一個Looper.prepareMainLooper(),此時會創(chuàng)建Looper對象和MessageQueue對象,當在UI線程new Handler()時渡贾,此時逗宜,Handler與Looper,MessageQueue建立關(guān)聯(lián),這個纺讲,當子線程handler.sendMessage(message)時擂仍,Looper.loop()會在messageQueue循環(huán)讀取對象Message msg=queue.next(),然后分發(fā)消息給Handler,有他來處理消息msg.target.dispatchMessage(msg),最后調(diào)用handleMessage(msg)處理消息,更細UI線程熬甚。

助理小怡(Looper)

助理小怡的工作內(nèi)容主要有兩件事情逢渔,第一件事情是做好準備工作(Looper.prepare()),即到某寶上包郵購買了一個消息盒子(MessageQueue)乡括,用來收集攻城獅們(Thread)的各種訴求(Message)复局。第二件事情是開啟無限循環(huán)的工作模式(Looper.loop()),她無比勤勞的等待著攻城獅們的各種召喚粟判,收集他們的訴求,并傳達給技術(shù)總監(jiān)峦剔。

技術(shù)總監(jiān)(Handler)
助理Looper在loop()中通過msg.target.dispatchMessage(msg)將消息分發(fā)給技術(shù)總監(jiān)Handler档礁,那么Handler將如何對這些Message進行處理.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吝沫,隨后出現(xiàn)的幾起案子呻澜,更是在濱河造成了極大的恐慌,老刑警劉巖惨险,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羹幸,死亡現(xiàn)場離奇詭異,居然都是意外死亡辫愉,警方通過查閱死者的電腦和手機栅受,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恭朗,“玉大人屏镊,你說我怎么就攤上這事√等” “怎么了而芥?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長膀值。 經(jīng)常有香客問我棍丐,道長,這世上最難降的妖魔是什么沧踏? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任歌逢,我火速辦了婚禮,結(jié)果婚禮上悦冀,老公的妹妹穿的比我還像新娘趋翻。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布踏烙。 她就那樣靜靜地躺著师骗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪讨惩。 梳的紋絲不亂的頭發(fā)上辟癌,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天,我揣著相機與錄音荐捻,去河邊找鬼黍少。 笑死,一個胖子當著我的面吹牛处面,可吹牛的內(nèi)容都是我干的厂置。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼魂角,長吁一口氣:“原來是場噩夢啊……” “哼昵济!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起野揪,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤访忿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后斯稳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體海铆,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年挣惰,在試婚紗的時候發(fā)現(xiàn)自己被綠了卧斟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡憎茂,死狀恐怖唆涝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情唇辨,我是刑警寧澤廊酣,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站赏枚,受9級特大地震影響亡驰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜饿幅,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一凡辱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧栗恩,春花似錦透乾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捧韵。三九已至,卻和暖如春汉操,著一層夾襖步出監(jiān)牢的瞬間再来,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工磷瘤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芒篷,地道東北人。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓采缚,卻偏偏與公主長得像针炉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子扳抽,可洞房花燭夜當晚...
    茶點故事閱讀 45,573評論 2 359

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