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

来源:互联网 发布:com用来表示什么域名 编辑:程序博客网 时间:2024/06/16 11:51

从官方推荐的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。

原创粉丝点击