Android 的消息机制主要是指Handler得运行机制
以上模型的解释:
1.以Handler的sendMessage方法为例,当发送一个消息后,会将此消息加入消息队列MessageQueue中。
2.Looper负责去遍历消息队列并且将队列中的消息分发给对应的Handler进行处理。
3.在Handler的handleMessage方法中处理该消息,这就完成了一个消息的发送和处理过程。
这里从图中可以看到参与消息处理有四个对象,它们分别是 Handler, Message, MessageQueue,Looper。
下面我们就围绕着这四个主要对象,来看下handler的运行机制,以及手写一个简易的handler消息机制。
Android消息处理机制- 一、创建全局唯一Looper对象和全局唯一MessageQueue消息对象:
- 二、Activity中创建Handler
- 三、消息发送,Message进入MessageQueue队列
- 四、消息处理,looper循环获取message消息处理
- 五、消息分发到自己的handlerMessage()方法
其实主要就是上面流程中的四个对象的创建。
- 一、MessageQueue就是负责message消息的入队和出队,很简单,我们用一个阻塞队列来实现
public class DnMessageQueue {
//阻塞队列
BlockingQueue blockingQueue = new ArrayBlockingQueue(50);
public void enqueueMessage(DnMessage message) {
try {
blockingQueue.put(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//从消息队列中取出消息
public DnMessage next() {
try {
return blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
- 二、上面是我们接收handler发出消息的容器,也就是存放message的地方,下面就要创建handler的消息入队操作,就是平时我们使用的mHandler.sendMessage(message)方法中的message对象通过handler的enqueue方法添加到消息队列的容器中:
public class DnHandler {
private DnLooper dnLooper;
private DnMessageQueue dnMessageQueue;
public DnHandler() {
dnLooper = DnLooper.myLooper();
if (dnLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
dnMessageQueue = dnLooper.mQueue;
}
public void handleMessage(DnMessage msg) {
}
public void sendMessage(DnMessage message) {
//将消息放入消息队列
enqueueMessage(message);
}
private void enqueueMessage(DnMessage message) {
//赋值当前消息
message.target = this;
//使用dnMessageQueue,将消息传入
dnMessageQueue.enqueueMessage(message);
}
public void dispatchMessage(DnMessage message) {
handleMessage(message);
}
}
这里的handler类的作用主要两点:一是enQueue消息到消息队列中;二是消息分发给对应的target。
- 三、消息入队后,就轮到looper上场行进消息队列的轮询,将加入到消息队列中的消息取出来
public class DnLooper {
static final ThreadLocal sThreadLocal = new ThreadLocal();
final DnMessageQueue mQueue;
private DnLooper(){
mQueue = new DnMessageQueue();
}
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one DnLooper may be created per thread");
}
sThreadLocal.set(new DnLooper());
}
public static DnLooper myLooper() {
return sThreadLocal.get();
}
public static void loop() {
//从全局ThreadLocalMap中获取唯一, looper对象
DnLooper dnLooper = myLooper();
DnMessageQueue mQueue = dnLooper.mQueue;
while (true){
DnMessage message = mQueue.next();
if(message != null ){
message.target.dispatchMessage(message);
}
}
}
}
- 四、其中的Message对象
public class DnMessage {
//消息标志
public int what;
//消息内容
public Object obj;
//Handler对象
public DnHandler target;
}
- 五、最终,为了使用我们自己的handler消息机制,我们测试类的入口是需要写在工程的test中,使用注解@Test来执行。因为要是再工程中的话程序在ActivityThread中会帮我们创建系统的handler。
public class DNActivityThread {
@Test
public void main(){
//创建全局唯一主线程Looper对象
DnLooper.prepare();
//创建Handler对象
final DnHandler dnHandler = new DnHandler(){
@Override
public void handleMessage(DnMessage msg) {
super.handleMessage(msg);
System.out.println(msg.obj.toString());
}
};
new Thread(new Runnable() {
@Override
public void run() {
DnMessage message = new DnMessage();
message.what = 1;
message.obj = "大家好!";
dnHandler.sendMessage(message);
}
}).start();
//获取消息
DnLooper.loop();
}
}
运行后,我们可以看到会打印出“大家好”这条消息。当然这个handler只是一个简化版的,为了理解handler消息机制的运行,系统的handler还有挂起、唤醒、延迟插入消息等完善的处理方案。
本项目地址:https://github.com/buder-cp/DesignPattern/tree/master/buder_DN_handler_thread
相关的handler学习博客推荐:
基础篇:
https://www.jianshu.com/p/b4d745c7ff7a?tdsourcetag=s_pcqq_aiomsg
深入篇:
https://blog.csdn.net/qian520ao/article/details/78262289#1-looper-%E6%AD%BB%E5%BE%AA%E7%8E%AF%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E4%BC%9A%E5%AF%BC%E8%87%B4%E5%BA%94%E7%94%A8%E5%8D%A1%E6%AD%BB?tdsourcetag=s_pcqq_aiomsg