2.消息事件分发
什么是消息机制,概述:
Android的消息机制主要是指Handler的运行机制,以及Handler所附带的MessageQueue和Looper的工作过程。即:消息的发送,以及消息的分发过程。
为什么需要消息机制:
Android规定访问UI只能在主线程中进行,在子线程中访问UI就会抛异常。但是Android又不建议在主线程中做耗时操作,会可能导致ANR。所以,我们需要,能在子线程中做完耗时操作,然后去到主线程更新UI的办法。
Hander的主要作用是将一个任务切换到指定的线程中去执行。因此,系统提供Handler主要是为了解决在子线程中无法访问UI的问题。
发送消息:
handler中有众多的send方法,时间点的区别而已,到最后都会调用下面的方法,把message放入消息队列
//handler.post view.post中的参数都是一个runnable对象,分装成一个Message
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
//msg插入队列
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//注意此处,this指的是handler自己
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//把消息插入队列
return queue.enqueueMessage(msg, uptimeMillis);
}
分发消息:
loop将队列中的msg一个一个取出,分发到各自的handler中处理。handler根据是否有callback选择不同的分发方式。
//Looper.loop(),省略了部分代码
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
//死循环。唤醒/挂起?
for (;;) {
//next方法会阻塞线程,有消息就取出,没消息就等待。
Message msg = queue.next();
//加入消息队列时,target == handler,分发的时候就可以找到原来的handler,让其自己处理。
//所以,一个线程多个handler发送消息,虽然都在一个队列里,但是还是会分发到原来的handler处理消息。
msg.target.dispatchMessage(msg);
}
}
//由target返回到Handler中执行分发。
//加入队列的:有的是Runnable封装的message,有的是callback,有的是message,在这里分发
public void dispatchMessage(Message msg) {
//runnable封装的message。 handler.post/view.post
if (msg.callback != null) {//msg中的callback 优先级1
handleCallback(msg);
} else {
if (mCallback != null) {
//Handler(Callback callback)的时候,mCallback !=null
if (mCallback.handleMessage(msg)) {//handler中的callback,优先级2
return;
}
}
//正常的message那种形式,也即是new Handler时复写的方法。
handleMessage(msg);// 优先级3
}
}
优先级:依次降低。
- 优先级1:
view.post(runnable)和handler.post(runnable)。最后runnable都会分装成Message。分发的时候,在第一处调用。
//封装成Message
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
//分发调用
//注意:虽然时runnable,但是,并不是新的线程哈。Thread的start()方法才是开启了新的线程,此处的run()就是正常的方法。
//Runnable中不要做耗时操作。
private static void handleCallback(Message message) {
message.callback.run();
}
-
优先级2:
Handler(Callback callback)的时候,赋值,mCallback !=null。
Callback的作用,源码中说明,就是用来创建一个Handler实例,但是并不需要派生Handler子类。提供了另外一种方式使用Handler。
(不用派生Handler子类了,但是一样需要一个CallBack对象啊,并没有什么区别简化好嘛)。 -
优先级3:
就是那种常用的obtain一个Message,设置what,obj参数,发送的消息。
退出:
public static void loop() {
//死循环。唤醒/挂起?
for (;;) {
//next方法会阻塞线程,有消息就取出,没消息就等待。
Message msg = queue.next();
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
}
}
分发机制loop()是一个死循环,唯一跳出来的办法是消息队列的next方法返回null。否则,next方法会有消息就唤醒,取出msg分发,没消息就阻塞等待。
图解
- Handler通过sendMessage()发送Message到MessageQueue队列;
- Looper通过loop(),不断提取出达到触发条件的Message,并将Message交给target来处理;
- 经过dispatchMessage()后,交回给Handler的handleMessage()或者runnable来进行相应地处理。
一个线程中的handler发送的消息,会不会跑到另外线程的MessageQueue队列中?
不会的,线程,Looper,队列三者一一对应。
一个线程间的多个handler发送消息,机制是怎样的?
这多个handler发送的消息会在同一个消息队列中,但是加入队列时"msg.target = this",会在Looper分发消息时" msg.target.dispatchMessage(msg)",分发到原来的handler中处理。