Handler事件分发机制

来源:互联网 发布:淘宝客服聊天话术技巧 编辑:程序博客网 时间:2024/06/05 06:38

Handler基础

Handler事件分发相关类

1.Message:消息对象,可通过Bundle存储数据及Runable存储业务逻辑。   Message的属性:      long when;        Handler target;        Runnable callback;2.Handler:发送,分发及处理Message。   Handler的属性:        MessageQueue mQueue;        Looper mLooper;        Callback mCallback;3.MessageQueue:消息队列,保存Handler发送的消息。4.Looper:循环从MessageQueue中读取消息交给Handler分发。   Looper的属性:        MessageQueue mQueue;        Thread mThread;5.ThreadLocal:保证每一个Thread中只有一个Looper。

发送Message相关函数

1.post(Runnable r):发送一个存储了业务逻辑的Message2.postAtTime(Runnable r, long uptimeMillis):可设置“精确”时间,在你设置的这个时间之前,不会被MessageQueue next()出来给Looper3.postAtTime(Runnable r, Object token, long uptimeMillis)4.postDelayed(Runnable r, long delayMillis):发送延迟消息,内部调用是这样的sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)5.postAtFrontOfQueue(Runnable r):发送一个排在队列之前的Message,也就是说不管发送这个Message之前MessageQueue中有多少Message,下一个被处理的就是现在发送的消息。6.sendMessage(Message msg)7.sendEmptyMessage(int what)8.sendEmptyMessageDelayed(int what, long delayMillis)9.sendEmptyMessageAtTime(int what, long uptimeMillis)10.sendMessageDelayed(Message msg, long delayMillis)11.sendMessageAtTime(Message msg, long uptimeMillis)12.sendMessageAtFrontOfQueue(Message msg)

Handler消息机制分发及处理流程分析

建立Handler消息机制

在Looper源码注释中有这么一段告诉了我们在普通Thread中怎么去使用Looper来建立Handler消息机制,我加入了Callback回调,以便下面的处理流程分析

class LooperThread extends Thread {    public Handler mHandler;    public void run() {        Looper.prepare();//准备Looper                Callback callback = new Callback(){                    public boolean handleMessage(Message msg){                        return false;                    }                };        mHandler = new Handler(callback) {//实例化Hanlder            public void handleMessage(Message msg) {                // process incoming messages here            }        };        Looper.loop();//开启循环读取消息    }}

发送Message

发送消息的函数有很多,这里以post()函数为例子

mHnalder.post(new Runable(){    public void run(){        Log.d("tag_log","Runable执行了");    }})

发送一个Runable消息就是这样的了,接下来看下post()干了些什么:

public final boolean post(Runnable r) {  return sendMessageDelayed(getPostMessage(r), 0);}/**将Runable赋值给Message**/private static Message getPostMessage(Runnable r) {  Message m = Message.obtain();//从消息池中获取一个Message对象  m.callback = r;  return m;}public final boolean sendMessageDelayed(Message msg, long delayMillis) {    if (delayMillis < 0) {        delayMillis = 0;    }    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}public boolean sendMessageAtTime(Message msg, long uptimeMillis) {    MessageQueue queue = mQueue;    if (queue == null) {        RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");        Log.w("Looper", e.getMessage(), e);        return false;    }    return enqueueMessage(queue, msg, uptimeMillis);}/**将Message压入MessageQueue消息队列**/private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  msg.target = this;//记录发消息的Handler,自己发的消息自己分发自己处理  if (mAsynchronous) {      msg.setAsynchronous(true);  }  return queue.enqueueMessage(msg, uptimeMillis);}

post()做了3件事情
1. 用Message包装Runable
2. 绑定发送Message的Hanlder对象
3. 将消息压入MessageQueue
从源码可以看出,不管事用post还是send去发送消息,最后都是将一个Message压入到MessageQueue。到此,消息的发送就已经结束了。那么是谁来从MessageQueue中拿Message又交给谁去处理呢?

Message分发及处理

在建立消息机制的时候有这么一段代码

    Looper.loop();//开启循环读取消息

这里就是Message分发的源头了,来看下它到底干了些什么

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;        ...    /**死循环不断读取及分发Message**/    for (;;) {        Message msg = queue.next(); //从队列中读取消息        if (msg == null) {            // No message indicates that the message queue is quitting.            return;        }                ...        /**将Message交给Handler分发**/        msg.target.dispatchMessage(msg);                ...        /**消息处理结束,进行回收**/        msg.recycleUnchecked();    }}

loop()就做了3件事情
1. 读取消息
2. 将Message给msg.target分发
3. 将处理完成的Message回收
消息分发就在这里msg.target.dispatchMessage(msg),在enqueueMessage()函数中我们知道msg.target就是发送这个Message的Hanlder对象,所以到最后Message的分发还是Handler自己来处理的,好吧那我们来看下它是怎么分发消息的?

public void dispatchMessage(Message msg) {    if (msg.callback != null) {/**Message的Runable不为null,则直接运行Runable对象**/            handleCallback(msg);    } else {/**Message的Runable为null**/            if (mCallback != null) {/**若Handler的Callback不为null,则将消息交给Callback处理**/                    if (mCallback.handleMessage(msg)) {                            /**如果Runable处理该消息之后返回true,则结束该消息的分发**/                            return;                    }            }            /**如果Runable处理该消息之后返回false,则继续将消息传递给Handler的handleMessage()处理,结束该消息的分发**/            handleMessage(msg);    }}private static void handleCallback(Message message) {        message.callback.run();}

看到了吧,到最后Message还是Handler自己来处理的。印证了enqueueMessage()中的那句注释,自己发送的消息自己分发自己处理。

Handler设置时间问题

起因

在查看源码的过程中,我发现Handler中是使用SystemClock.uptimeMillis()函数来获取时间,而平常我设置时间间隔一般都使用System.currentTimeMillis(),问题来了:
1. 那这两种方法有何区别呢?
2. 如果在postAtTime(Runnable r, long uptimeMillis)的时候使用System.currentTimeMillis()会怎么样?

区别

1. SystemClock.uptimeMillis()是从开机到现在的毫秒数(手机睡眠的时间不包括在内);2. System.currentTimeMillis()是从1970年1月1日 UTC到手机当前时间的毫秒数;

但是,第2个时间,是可以通过System.setCurrentTimeMillis修改的,那么,在某些情况下,一但被修改,时间间隔就不准了。

能使用?

测试一

Handler handler = new Handler();handler.postAtTime(new Runnable() {    @Override    public void run() {        Log.d("tag_log", "Runnable执行了");    }},SystemClock.uptimeMillis());

Log正常打印出来了。

测试二

Handler handler = new Handler();handler.postAtTime(new Runnable() {    @Override    public void run() {        Log.d("tag_log", "Runnable执行了");    }},System.currentTimeMillis());

等了很久Log就是打印不出来了。这是为什么呢?

解决问题

最后跟踪源码发现传入的参数uptimeMillis赋值给了Message的when属性,而在MessageQueue的next()函数中有这么一段:

Message next() {...for (;;) {    ...    final long now = SystemClock.uptimeMillis();    Message prevMsg = null;    Message msg = mMessages;    ...    if (msg != null) {            //msg.when就是我们设置的时间        if (now < msg.when) {            ...        } else {            ...            msg.markInUse();            return msg;        }    } else {        ...    }}}

也就是说,你给Message设置的时间比现在的SystemClock.uptimeMillis()时间大的话,next()函数就不会将你返回给Looper分发处理。随即我打印这两个时间做对比

tag_log: SystemClock.uptimeMillis():2546808tag_log: System.currentTimeMillis():1461813573568

我靠System.currentTimeMillis()大太多了,所以说,如果我们在这里使用System.currentTimeMillis()的话,now < msg.when很长一段时间内都为true(在不手动System.setCurrentTimeMillis的话),这样我们发送的Message在手机不关机的几十年里也得不到执行了。我就是System.currentTimeMillis盲目使用者,幸运的是我以前只发送过延迟消息。。。。

0 0
原创粉丝点击