- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
SendMessage
我们使用 Handler 发送消息
mHandler.sendMessage(msg);
Handler 有好多相关的发送消息的方法。但是追踪源码,发现他们最终都来到了 Handler 的这个方法 sendMessageAtTime
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); }
接着看 enqueueMessage() 方法体
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; // 使用默认的 handler 构造方法时,mAsynchronous 为 false。 if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
这里有一句至关重要的代码
msg.target = this;
我们看看 msg 的 target 是怎么声明的
Handler target;
意思就是每个 Message 都有一个类型为 Handler 的 target 对象,这里在 handler 发送消息的时候,最终执行到 上面的方法 enqueueMessage() 时,会自动把当前执行 sendMessage() 的 handler 对象,赋值给 Message 的 target。
也就是说,Handler 发送了 Message,并且这个 Message 的 target 就是这个 Handler。
想想为什么要这么做?
这里再说一下,Handler 的作用,
- 发送消息
- 处理消息
先不看代码,我们可以想想,handler 发送了 message ,最终这个 message 会被发送到 MessageQueue 这个消息队列。 那么最终,谁会去处理这个消息。
在这里消息发送和处理遵循『谁发送,谁处理』的原则。现在问题来了,就按照上面说的,谁发送,谁处理,那现在应该是 handler 自己处理了,但是他在哪里处理呢?到现在我们也没看到啊。慢慢来,接下来继续看消息的传递。
现在,我们只要发送了消息,那么消息池 mQueue 就会增加一个消息,Looper 就会开始工作,之前已经说了,在应用启动的时候, 已经启动了 Looper 的 loop() 方法,这个方法会不断的去轮训 mQueue 消息池,只要有消息,它就会取出消息,并处理,那他是怎么处理的呢?看一下 loop() 的代码再说。
public static void loop() { //获得一个 Looper 对象 final Looper me = myLooper(); // 拿到 looper 对应的 mQueue 对象 final MessageQueue queue = me.mQueue; //死循环监听(如果没有消息变化,他不会工作的) 不断轮训 queue 中的 Message for (;;) { // 通过 queue 的 next 方法拿到一个 Message Message msg = queue.next(); // might block //空判断 if (msg == null)return; //消息分发 msg.target.dispatchMessage(msg); //回收操作 msg.recycleUnchecked(); } }
看 for() 循环,他在拿到消息后,发现 msg 不为空,接着就会执行下面这句非常重要的代码
msg.target.dispatchMessage(msg);
这里执行了 msg.target 的方法 dispatchMessage,上面已经在 sendMessage 时看到了,我们在发送消息时,会把 msg 的 target 设置为 handler 本身,也就是说,handler 发送了消息,最终自己处理了自己刚刚分发的消息。恩恩,答案就在这里,『谁发送,谁处理』的 道理在这里终于得到了体现。
那么他是怎么处理消息的?看看 Handler 的 dispatchMessage() 是怎么实现的。
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
我们看到,我们没有给 msg 设置 callback 也没有给 handler 的 mCallback 设置过值,所以此时,会执行 handleMessage() 方法;
public void handleMessage(Message msg) { }
发现这是一个空方法,所以自己的新建 Handler 时,只要复写了这个方法,我们就可以接受到从子线程中发送过来的消息了 。在看一遍自己定义 Handler 时,如何定义的,如何复写 handlerMessage
private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 1: Bitmap bitmap = (Bitmap) msg.obj; imageView.setImageBitmap(bitmap); break; case -1: Toast.makeText(MainActivity.this, "msg "+msg.obj.toString(), Toast.LENGTH_SHORT).show(); break; } } };
在这里,我们处理了自己发送的消息,到此 Handler 的内部机制大体就分析完了。但是从上面的 dispatchMessage 方法我们也能看出,Handler 在处理消息时的顺序是什么?
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
他首先判断 Message 对象的 callback 对象是不是为空,如果不为空,就直接调用 handleCallback 方法,并把 msg 对象传递过去,这样消息就被处理了,我们来看 Message 的 handleCallback 方法:
private static void handleCallback(Message message) { message.callback.run(); }
没什么好说的了,直接调用 Handler post 的 Runnable 对象的 run() 方法。
如果在发送消息时,我们没有给 Message 设置 callback 对象,那么程序会执行到 else 语句块,此时首先判断 Handler 的 mCallBack 对象是不是空的,如果不为空,直接调用 mCallback 的 handleMessage 方法进行消息处理。
最终,只有当 Handler 的 mCallback 对象为空,才会执行自己的 handleMessage 方法。
这是整个处理消息的流程。现在就会想了,在处理消息时,什么时候才能执行到第一种情况呢,也就是通过 Message 的 callback 对象处理。其实简单,查看源码发现
/*package*/ Runnable callback;
callback 是一个 Runnable 接口,那我们这怎么才能设置 Message 的 callback 的参数呢?最后观察发现,Handler 发送消息时,除了使用 sendMessage 方法,还可以使用一个叫 post 的方法,而他的形参正好就是 Runnable,我们赶紧拔出他的源码看看。
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
接着看 getPostMessage() 这个方法。
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
代码看到这里,已经很清楚了,getPostMessage() 返回了一个 Message 对象,这个对象中设置了刚才传递过来的 runnable 对象。
到这里,你应该明白了,在处理消息时,除了 Handler 自身的 handlerMessage() 方法设置处理,还可以直接在发消息时指定一个 runnable 对象用于处理消息。
另外上面通过 dispatchMessage() 的代码已经看出来,处理消息有三种情形,第一种直接使用 Message 的 running 对象处理,如果不行使用第二种 用 Handler 的 mCallback 对象处理,最后才考虑使用 handlerMessage 处理,关于第二种情形,这里就不分析了,自己试着看代码应该能找到。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论