Handler、Looper、MessageQueue源码解析——Handler



Handler


Handler 是Android中常用的异步通信的一个类,Android是一个消息驱动的操作系统,各种类型的消息都是由Handler发出,再由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时只能用前四个构造方法。)

根据传入参数的不同,最后都会调用这两个构造方法:

``` java
//没有传Looper
Handler(Callback callback, boolean async)
//传了Looper
Handler(Looper looper, Callback callback, boolean async)```

至于Looper是什么,接下来再解释。

看一下```Handler(Callback callback, boolean async)```这个构造函数:

``` java

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

    ...

    public Handler(Callback callback, boolean async) {
        //检查Handler类型,提示是否出现内存泄漏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)```这个构造函数呢?

``` java
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }```
没错,区别就是Looper对象通过我们传进来的Looper对象来指定。

既然Handler是发送消息和处理消息的,那么Handler是怎么发送消息的呢?

官方为我们提供了这些方法:

```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)```。

但是第一个参数传进去的是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)```

说完了发送消息,接下来说一下处理消息。

在Looper的 ``` loop()``` (开启消息循环)方法有这样一段代码:
try {
    msg.target.dispatchMessage(msg);
} finally {
    if (traceTag != 0) {
        Trace.traceEnd(traceTag);
    }
}```

我们已经知道message的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方法发送的消息会给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不为空,会执行callback的handleMessage方法,如果callback为空,则执行Handler的handleMessage方法,这两个方法的实现都为空,需要我们自己去实现。

Handler的源码大部分就是这么多,其余的就是一些removeCallback之类的方法。Handler的主要功能就是这些。接下来我们来学习其他两个很重要的类Looper。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容