Android日記之消息機(jī)制(1)

前言

在網(wǎng)上看到許多的關(guān)于Android消息機(jī)制的講解秽荤,覺的還是自己重新看書并自己寫一篇來理解會(huì)更好,消息機(jī)制的內(nèi)容也是在面試中最容易被問到的內(nèi)容课锌,因?yàn)橄C(jī)制的內(nèi)容比較多罐旗,我會(huì)分成好幾篇來進(jìn)行講解,有錯(cuò)誤也請(qǐng)大家多多包涵并指出位迂。

消息機(jī)制是什么

從一般角度來說访雪,Android的開發(fā)機(jī)制指的就是Handler,它是Android消息機(jī)制的上層接口掂林,我們只需要對(duì)他進(jìn)行交互就好了臣缀,它也是Android開發(fā)中最經(jīng)常接觸的一個(gè)消息機(jī)制,Handler默認(rèn)關(guān)聯(lián)主線程泻帮,雖然要提供Runnable參數(shù) 精置,但默認(rèn)是直接調(diào)用Runnable中的run()方法。對(duì)于一些異步的耗時(shí)操作還有最重要的更新UI這些就都需要通過Handler來進(jìn)行實(shí)現(xiàn)锣杂,我們也就從這里開始入手脂倦。

Handler的基本使用

package com.ju.handlerdemo;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class HandlerActivity extends AppCompatActivity {


    private Button b1;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

            switch (msg.what) {
                case 1:
                    //這里更新業(yè)務(wù)邏輯或者更新UI
                    break;
                default:
                    break;
            }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        b1 = findViewById(R.id.button1);
        b1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread() {
                    @Override
                    public void run() {
                        Message message = new Message();
                        //這個(gè)是標(biāo)志,可以發(fā)送多個(gè)元莫,比如arg1,arg2等等狼讨。
                        message.what = 1;
                        handler.sendMessage(message);
                    }
                }.start();
            }
        });
    }
}

這里先創(chuàng)建了一個(gè)Handler的對(duì)象,并重寫了handleMessage()的方法柒竞,這個(gè)方法就是執(zhí)行主要的業(yè)務(wù)邏輯的政供,然后創(chuàng)建了一個(gè)子線程,在子線程里面創(chuàng)建了一個(gè)Message的對(duì)象朽基,這個(gè)Message就是Handler要處理的對(duì)象布隔,Message有多個(gè)字段。

public void testMessage(){
    Message message = new Message();
    //傳入的是int類型
    message.what = 1;
    message.arg1 = 2;
    message.arg2 = 3;
    //傳入的是Object類型
    message.obj = null;
}

我們發(fā)現(xiàn)不僅是可以傳入int值稼虎,其實(shí)也可以傳入Object的類型衅檀,這樣Handler就可以執(zhí)行一些更復(fù)雜的操作了,然后在通過sendMessage()這個(gè)方法來把消息發(fā)送出去霎俩,message對(duì)象就會(huì)傳到Handler的handleMessage()里根據(jù)字段進(jìn)行具體的業(yè)務(wù)邏輯處理哀军。注意的是Handler的handleMessage()這時(shí)候就已經(jīng)是在主線程中進(jìn)行了沉眶,而不是在子線程中進(jìn)行運(yùn)行。這就是最基本的使用方法了杉适。

Handler工作原理

這里我們就先不從源碼開始解析(因?yàn)樵创a有點(diǎn)多= =)谎倔,這里大概的講解一下Handler的工作原理,Handler主要就是由4個(gè)部分組成:Message猿推、Handler片习、MessageQueue和Looper。而Handler的運(yùn)行的底層就需要有
MessageQueue和Looper來進(jìn)行支撐蹬叭。我們一個(gè)個(gè)來看它們的作用藕咏。

  • Meesgae
    它就是Handler之間的傳遞的消息,是一個(gè)封裝了需要傳遞給Handler數(shù)據(jù)的對(duì)象秽五,也可以攜帶Object和int類型的消息來傳遞到Handler進(jìn)行處理孽查,剛剛上面也展示過了。

  • Handler
    它就是用來發(fā)送和處理消息的坦喘,一般都是通過sendMessage()sendEmptyMessageAtTime()來進(jìn)行發(fā)送消息盲再,擔(dān)任也有其他發(fā)送消息的方法,具體有什么區(qū)別我們稍后再講起宽,通過Handler進(jìn)行發(fā)送消息后洲胖,經(jīng)過一系列的處理,就會(huì)傳遞到handleMessage()里面去來進(jìn)行處理坯沪。

  • MessageQueue
    它是一個(gè)消息隊(duì)列绿映,是一個(gè)單鏈表,通過handler發(fā)送出來的消息都會(huì)傳遞到這個(gè)消息隊(duì)列里面腐晾,然后依次的被等待處理叉弦,每一個(gè)線程只會(huì)有一個(gè)MessageQueue。

  • Looper
    他是一個(gè)輪詢器藻糖,通過Looper的loop()方法淹冰,就會(huì)進(jìn)入到一個(gè)無限的循環(huán)中,然后當(dāng)MessageQueue里有一條待處理的消息巨柒,就會(huì)取出來分發(fā)到Handler的handleMessage()方法中進(jìn)行處理樱拴,每一個(gè)線程也只會(huì)有一個(gè)Looper對(duì)象。


    Handler消息機(jī)制原理洋满,侵刪

以上總結(jié)經(jīng)過Looper發(fā)送到handleMessage()的時(shí)候晶乔,也就代表了從子線程轉(zhuǎn)到了主線程,這樣就可以進(jìn)行UI的處理了牺勾,這里補(bǔ)充一句正罢,關(guān)于UI更新還有一個(gè)方法就是runOnUiThread()方法,它也是一個(gè)異步消息的接口封裝驻民,背后的原理其實(shí)跟上面描述的原理是一樣的翻具。

Message

發(fā)現(xiàn)沒有履怯,如果要進(jìn)行Handler的傳遞,就一定需要一個(gè)Message裆泳,但是如果每次需要調(diào)用的Handler的時(shí)候就創(chuàng)建一個(gè)Message實(shí)例化的話叹洲,又會(huì)非常的浪費(fèi)資源。其實(shí)創(chuàng)建Message有其它的方法晾虑。

//通過Handler取出Message
Message message1 = handler.obtainMessage();
//通過Message自帶的obtain()來取出Message
Message message2 = Message.obtain();

我們這里先看第一種的源碼吧

//Handler類
public final Message obtainMessage()
{
    return Message.obtain(this);
}

//Message類
public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;

    return m;
}

//也是第二種綁定方式的源碼
public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

Handler類里的obtainMessage()其實(shí)就是調(diào)用了Message的obtain()方法疹味,然后再去調(diào)用了Message內(nèi)部類的obtain()方法來返回Message仅叫。而第二種綁定方式就是直接調(diào)用了obtain()就直接創(chuàng)建了Message帜篇,這樣子的效率其實(shí)是會(huì)更高的,源碼這里發(fā)現(xiàn)其實(shí)Message是一個(gè)鏈表诫咱,這里判斷如果是空鏈表的話笙隙,就創(chuàng)建一個(gè)Message,然后將頭鏈表移除掉坎缭,將頭鏈表的下一個(gè)作為新的節(jié)點(diǎn)竟痰,并維護(hù)sPoolSize,sPoolSize就是節(jié)點(diǎn)數(shù)量掏呼,而且還加了個(gè)synchronized的鎖坏快。這樣子就減少了對(duì)Message的重復(fù)利用,也不會(huì)一直創(chuàng)建Message對(duì)象憎夷,提高了效率莽鸿。

obtain實(shí)現(xiàn)流程圖,侵刪




Handler的發(fā)送

Handler的發(fā)送方法有很多拾给,這里說幾個(gè)比較常見的祥得。

  • sendMessage(Message msg)
    這個(gè)也是基本的發(fā)送方式,傳入Message就可以發(fā)送到Handler進(jìn)行處理了蒋得。
  • sendEmptyMessage(int what)
    其實(shí)里面就是調(diào)用了sendEmptyMessageDelayed()這個(gè)方法傳入要識(shí)別的信息级及,只是這個(gè)信息是int類型的。
  • sendEmptyMessageDelayed(int what, long delayMillis)
    這個(gè)也是一樣的额衙,在sendEmptyMessage()里面其實(shí)就是調(diào)用了這個(gè)sendEmptyMessageDelayed()方法饮焦,第二個(gè)參數(shù)就是代表了消息發(fā)送的延時(shí)而已。

Handler的內(nèi)存泄露

其實(shí)如果直接調(diào)用重寫Handler的handlerMessage()是有可能會(huì)引起內(nèi)存泄露的窍侧,官方并不建議這樣使用Handler县踢,可以按照官方給出的解決辦法的使用方法。

private Handler mHandler = new Handler(new Handler.Callback() {  
         
       @Override  
       public boolean handleMessage(Message msg) {  
           return false;  
       }  
   });




參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疏之,一起剝皮案震驚了整個(gè)濱河市殿雪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锋爪,老刑警劉巖丙曙,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爸业,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡亏镰,警方通過查閱死者的電腦和手機(jī)扯旷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來索抓,“玉大人钧忽,你說我怎么就攤上這事”瓶希” “怎么了耸黑?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)篮幢。 經(jīng)常有香客問我大刊,道長(zhǎng),這世上最難降的妖魔是什么三椿? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任缺菌,我火速辦了婚禮,結(jié)果婚禮上搜锰,老公的妹妹穿的比我還像新娘伴郁。我一直安慰自己,他們只是感情好蛋叼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布焊傅。 她就那樣靜靜地躺著,像睡著了一般鸦列。 火紅的嫁衣襯著肌膚如雪租冠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天薯嗤,我揣著相機(jī)與錄音顽爹,去河邊找鬼。 笑死骆姐,一個(gè)胖子當(dāng)著我的面吹牛镜粤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玻褪,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼肉渴,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了带射?” 一聲冷哼從身側(cè)響起同规,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后券勺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绪钥,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年关炼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了程腹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡儒拂,死狀恐怖寸潦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情社痛,我是刑警寧澤见转,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站褥影,受9級(jí)特大地震影響池户,放射性物質(zhì)發(fā)生泄漏咏雌。R本人自食惡果不足惜凡怎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赊抖。 院中可真熱鬧统倒,春花似錦、人聲如沸氛雪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽报亩。三九已至浴鸿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間弦追,已是汗流浹背岳链。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劲件,地道東北人掸哑。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像零远,于是被迫代替她去往敵國(guó)和親苗分。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

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