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盲目使用者,幸运的是我以前只发送过延迟消息。。。。
- Handler事件分发机制
- 简述下handler分发机制
- Anroid中的事件处理Handler与事件分发机制举例子详细解释
- OnTouchEvent事件分发机制
- android事件分发机制
- Android事件分发机制
- Android 事件分发机制
- Android事件分发机制
- Android 事件分发机制
- Android 事件分发机制
- android 事件分发机制
- Android事件分发机制
- android 事件分发机制
- android事件分发机制
- Android 事件分发机制
- android事件分发机制
- 【cocos2dx事件分发机制】
- android 事件分发机制
- C++11
- UVa 814 The Lettter Carrier's Rounds
- nodejs express框架 中app.js
- ASPxGridView 导出和部分属性设置
- Android Studio:Error:(1, 0) Your project path contains non-ASCII characters. This will most likely c
- Handler事件分发机制
- 自定义用作头像的选择器
- Java Swing简单控件实例(JButton,JLabel,JMenuBar,JComboBo)
- 爬虫入门-待续
- hdu 4193(单调队列)
- RecyclerView重写网格的布局管理器
- 并发队列ConcurrentLinkedQueue和阻塞栈LinkedBlockingQueue用法和阻塞队列ArrayBlockingQueue
- PsSetCreateProcessNotifyRoutine进程黑名单
- ios微信点击超链接,去掉半透明黑色框效果