android中handler消息发送机制源码剖析

从官方推荐的handler用法说起:

class LooperThread extends Thread {
    public Handler mHandler;
    public void run() {
        Looper.prepare();
        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };
        Looper.loop();
    }

先不管为什么要Looper.prepare(),直接看看handler的构造函数,new Handler会进入到下面的构造函数:
这里写图片描述
其中对looper有个判断,如果为null会发生runtimeException导致崩溃,这个looper正是从Looper的sThreadLocal中取出来的:
这里写图片描述
sThreadLocal是什么?
这里写图片描述
我的理解是,它保存了每个线程和它相关的Looper,通过sThreadLocal.get()就能得到looper,而sThreadLocal是个静态变量,直接在声明时就初始化了,所以我们在每个线程中直接使用Looper.myLooper()就能得到初始化handler需要的mLlooper(有点啰嗦了……)。
所以我们要先整一个looper和当前线程绑定,looper的作用是运行一个message loop来管理消息队列:
这里写图片描述
回到主线,有了looper,有了handler,我们可以发送消息了。sendMessage有好几种方式,sendEmptyMessage、sendMessage(message)、sendMessageDelayed()、sendMessageAtTime(),都会进入下面这个函数:
这里写图片描述
先对mQueue作了判断,mQueue是在handler构造函数里初始化的:
这里写图片描述
mLooper里的mQueue是在looper.loop()时初始化的:
这里写图片描述
所以如果没有调looper.loop()也会崩溃;handler发的消息会进入queue.enqueueMessage():
这里写图片描述
MessageQueue.enqueueMessage的代码:

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

MessageQueue并不是保存了所有的message,它只保留了一个message(虽然名字是mMessages):
这里写图片描述
从MessageQueue的dump方法可以看出一些端倪:
这里写图片描述
对MessageQueue的遍历,是通过保存的mMessage和message.netx实现的,并不是从一个集合中依次取出的。
再回到MessageQueue.enqueueMessage,一开始作了两个判断,然后是if-else:
这里写图片描述
if里面的作用,其实是做一个插队的操作,when代表每个msg发送的时间,MessageQueue里是按时间排序的,如果p == null说明当前没有处理消息,自然要把传进来的msg优先处理:保存为mMessages,并把next置为null,至于mBlocked先看看定义:
这里写图片描述
是next()操作是否阻塞的标志,传给needWake,然后判断needWake:
这里写图片描述
翻译一下就是,如果next()阻塞,调用native方法唤醒,没看native代码,我猜,next阻塞,说明没有其它消息需要处理,系统不会再去查询队列,会把队列查询功能暂时“休眠”起来,当队列更新时,要判断当前系统是否在处理消息,如果没有处理处于“休眠”状态,需要被唤醒;如果本来就在处理,就无需调用native方法去唤醒。
再来看else里面的代码:
这里写图片描述
看注释就知道了,当前MessageQueue有message,并且message的入队时间在传进来的msg前面,需要按照时间顺序把msg插入到队列中间:一个死循环,直到最后一个message的next为null,或者找到队列中时间在传进来msg之后的message,才跳出循环,把msg的next指向这个message(就是插队)。
if-else之后就是判断是否需要唤醒,然后调用native方法。

上面说的是前半部分,handler发消息,然后handler会调用MessageQueue的enqueueMessage方法,把消息加入队列。


后半部分,就是把消息从MessageQueue中取出来并处理。

在标准用法中,最后一行:

Looper.loop();

前面说过,“looper的作用是运行一个message loop来管理消息队列”,那么上面就是对消息队列的操作了。我把源码精简下,去掉打印的代码:

/**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

    ...............................

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            ...................................

            msg.target.dispatchMessage(msg);

        ...................................

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();

            .....................................

            msg.recycleUnchecked();
        }
    }

Looper在prepare时,就创建了一个MessageQueue:
这里写图片描述

这里写图片描述
handler就是把message发到了这个mQueue,在Looper.loop()里有个死循环,不断从中取出下一个message,如果message不为null:

msg.target.dispatchMessage(msg);

msg的target是什么?是个Handler类对象,什么时候赋值的?handler的enqueueMessage:
这里写图片描述
这里,message和发送它的handler绑定在一起,下面看看handler的dispatchMessage:

这里写图片描述
由于我们使用的时候,没有定义msg的callback,这里会进入else,判断mCallback,其实handler的mCallback也是没有定义的,最后到了handleMessage():
这里写图片描述
handler没有实现,是由子类实现的,所以回到了一开始定义一个Handler,并override handleMessage的地方:

Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };

总结一下,handler,MessageQueue,Looper在整个流程中的作用:

  1. Looper.prepare():在当前线程绑定一个Looper,并初始化Looer中的MessageQueue;

  2. new Handler:初始化一个handler并实现handlerMessage,用于处理消息,并在构造函数中,取出本线程Looper中的MessageQueue赋值给自己的成员变量mQueue;

  3. handler.sendMessage:将message与handler绑定(msg.target = this),调用mQueue.enqueueMessage();

  4. mQueue.enqueueMessage():MessageQueue对消息队列中的消息重新排序(其实没有队列,是修改message.next和mMessages);

  5. Looper.loop():从当前线程中得到looper,(sThreadLocal.get()),取出looper中的mQueue,再用一个死循环从mQueue取出message(通过Message msg = queue.next()),得到message后,用它绑定的handler分发消息,(msg.target.dispatchMessage(msg)),dispatchMessage最终回到了new Handler时实现的handlerMessage。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值