Handler、Looper罢坝、MessageQueue源碼解析——Handler



Handler


Handler 是Android中常用的異步通信的一個類,Android是一個消息驅動的操作系統(tǒng)牲迫,各種類型的消息都是由Handler發(fā)出耐朴,再由Handler處理,那么對于Handler機制的理解就至關重要盹憎。

比如我們讓一個TextView延時3秒顯示"Hello World"筛峭,我們會這樣寫:

Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        mTextView.setText("Hello World");
    }
}, 3000);```

當我們new 一個Handler時,具體做了什么呢陪每?從源碼中我們可以得到
答案:

Handler共有7種構造方法:
```java
Handler() 

Handler(Callback callback)

Handler(Looper looper)

Handler(Looper looper, Callback callback)

/**@hide*/
Handler(boolean async)

/**@hide*/
Handler(Callback callback, boolean async)

/**@hide*/
Handler(Looper looper, Callback callback, boolean async)```

(注意@hide注解影晓,表示這些API是不對外開放的,但是在運行的時候是可以使用這些API檩禾。雖然也是public的俯艰,但是不能直接調用,也無法通過反射獲取锌订。所以我們在使用Handler時只能用前四個構造方法。)

根據(jù)傳入?yún)?shù)的不同画株,最后都會調用這兩個構造方法:

``` java
//沒有傳Looper
Handler(Callback callback, boolean async)
//傳了Looper
Handler(Looper looper, Callback callback, boolean async)```

至于Looper是什么辆飘,接下來再解釋。

看一下```Handler(Callback callback, boolean async)```這個構造函數(shù):

``` java

    final Looper mLooper;
    final MessageQueue mQueue;
    final Callback mCallback;
    final boolean mAsynchronous;

    ...

    public Handler(Callback callback, boolean async) {
        //檢查Handler類型谓传,提示是否出現(xiàn)內存泄漏warning
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
        
        // 得到Looper對像蜈项,稍后解釋
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //獲得MessageQueue對象
        mQueue = mLooper.mQueue;
        //設置callback
        mCallback = callback;
        mAsynchronous = async;
    }```
首先通過```Looper.myLooper()```獲得Looper對象,再通過Looper對象獲取與Looper綁定的MessageQueue對象续挟。

那么```Handler(Looper looper, Callback callback, boolean async)```這個構造函數(shù)呢紧卒?

``` java
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }```
沒錯,區(qū)別就是Looper對象通過我們傳進來的Looper對象來指定诗祸。

既然Handler是發(fā)送消息和處理消息的跑芳,那么Handler是怎么發(fā)送消息的呢?

官方為我們提供了這些方法:

```java
public final boolean post(Runnable r)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
public final boolean sendMessage(Message msg)
public final boolean sendEmptyMessage(int what)
public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
public boolean sendMessageAtTime(Message msg, long uptimeMillis)```

看起來很多直颅,其實最后都調用了一個方法```sendMessageAtTime(Message msg, long uptimeMillis)```博个。

什么?道理我都懂功偿,post(Runnable r)是個什么東西盆佣?
其實post一系列方法最后調用的還是```sendMessageAtTime(Message msg, long uptimeMillis)```。

但是第一個參數(shù)傳進去的是getPostMessage(r)
``` java
    private static Message getPostMessage(Runnable r) {
    //從Message pool里獲得一個Message或者新建一個Message對象
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

可以看出Runnable是Message的callback。Runnable callback是Message的一個成員變量共耍,所以postXXX方法就是對Message的一個封裝虑灰。

那么我們重點看一下sendMessageAtTime方法。

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    //從Looper中獲得的MessageQueue
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }s
        return enqueueMessage(queue, msg, uptimeMillis);
    }```

最后調用enqueueMessage方法:
``` java
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }```

target是Message的一個Handler類型的成員變量痹兜。所以sendMessageAtTime方法就是獲取MessageQueue穆咐,并為Message對象設置target屬性,然后把message插入到MessageQueue中佃蚜。

Handler也提供了另外兩個方法庸娱,直接把消息插入到消息隊列第一個:
  ```java
public final boolean postAtFrontOfQueue(Runnable r)
public final boolean sendMessageAtFrontOfQueue(Message msg)```

說完了發(fā)送消息,接下來說一下處理消息谐算。

在Looper的 ``` loop()``` (開啟消息循環(huán))方法有這樣一段代碼:
try {
    msg.target.dispatchMessage(msg);
} finally {
    if (traceTag != 0) {
        Trace.traceEnd(traceTag);
    }
}```

我們已經(jīng)知道m(xù)essage的target是一個Handler對象熟尉,消息的處理也就是調用了Handler的dispathMessage方法:

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }```
首先判斷message的callback是否為空,即我們通過postXXX方法發(fā)送的消息會給Message加上一個callback即Runnable洲脂,如果不為空調用handleCallback(msg):
``` java
    private static void handleCallback(Message message) {
        message.callback.run();
    }```
也就是調用Runnable的run()方法斤儿。

如果Message的Callback為空,接下來判斷mCallback是否為空恐锦,mCallback是什么呢往果,回到Handler的構造方法,當我們調用這兩個構造方法```Handler(Callback callback) , Handler(Looper looper, Callback callback)```時一铅,我們會為Handler指定一個callback陕贮,當Handler的callback不為空,會執(zhí)行callback的handleMessage方法潘飘,如果callback為空肮之,則執(zhí)行Handler的handleMessage方法,這兩個方法的實現(xiàn)都為空卜录,需要我們自己去實現(xiàn)戈擒。

Handler的源碼大部分就是這么多,其余的就是一些removeCallback之類的方法艰毒。Handler的主要功能就是這些筐高。接下來我們來學習其他兩個很重要的類Looper。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末丑瞧,一起剝皮案震驚了整個濱河市柑土,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绊汹,老刑警劉巖冰单,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異灸促,居然都是意外死亡诫欠,警方通過查閱死者的電腦和手機涵卵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荒叼,“玉大人轿偎,你說我怎么就攤上這事”焕” “怎么了坏晦?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嫁乘。 經(jīng)常有香客問我昆婿,道長,這世上最難降的妖魔是什么蜓斧? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任仓蛆,我火速辦了婚禮,結果婚禮上挎春,老公的妹妹穿的比我還像新娘看疙。我一直安慰自己,他們只是感情好直奋,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布能庆。 她就那樣靜靜地躺著,像睡著了一般脚线。 火紅的嫁衣襯著肌膚如雪搁胆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天邮绿,我揣著相機與錄音渠旁,去河邊找鬼。 笑死斯碌,一個胖子當著我的面吹牛,可吹牛的內容都是我干的肛度。 我是一名探鬼主播傻唾,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼承耿!你這毒婦竟也來了冠骄?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤加袋,失蹤者是張志新(化名)和其女友劉穎凛辣,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體职烧,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡扁誓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年防泵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝗敢。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡捷泞,死狀恐怖,靈堂內的尸體忽然破棺而出寿谴,到底是詐尸還是另有隱情锁右,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布讶泰,位于F島的核電站咏瑟,受9級特大地震影響,放射性物質發(fā)生泄漏痪署。R本人自食惡果不足惜码泞,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惠桃。 院中可真熱鬧浦夷,春花似錦、人聲如沸辜王。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呐馆。三九已至肥缔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間汹来,已是汗流浹背续膳。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留收班,地道東北人坟岔。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像摔桦,于是被迫代替她去往敵國和親社付。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內容