Handler 消息发送机制实现原理解析
对于Handler消息发送机制,相信大家都不陌生,但是怎么发送可能就不是太清楚了,为了加深印象特此总结,个人总结一句话:
向哪个线程发送消息就在哪个线程中创建Handler。
我们大多数情况都是在子线程向主线程发送消息,一般都没什么问题。但是怎么从主线程向子线程发送消息呢?
咱们先创建一个子线程
var thread = Thread(object :Runnable{
override fun run() {
// Looper.prepare()
mHandlerTwo = object : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (msg.what==201){
ToastUtils.showShort(msg.obj.toString())
}
}
}
// Looper.loop()
}
}).start()
然后在主线程中添加点击事件发送信息
var msg = Message.obtain()
msg.what=201
msg.obj = "收到主线程中的信息"
mHandlerTwo.sendMessage(msg)
当我们点击后发现会没有反应或者抛异常
从给出来的信息我们可以看到,创建Handler的前提是必须先执行Looper.prepare(),但是我们为啥在主线程创建Handler时不需要Looper.prepare(),因为主线程中系统已经帮我们实现了这个方法。大家都知道App也有入口,是Main函数,但是我们的Main函数在哪儿呢?我们看ActivityThread这个类,搜索Main如图:
这里的Looper.prepareMainLooper() 就相当于Looper.prepare(),所以我们在主线程中不需要在添加Looper.prepare()方法Handler也可以正常收发消息。
个人总结 Handler通信之前三步骤:
一、调用Looper.prepare()
二、创建Handler对象
三、调用Looper.loop()
Handl 消息发送机制
主要涉及到四个类
1、Looper:消息遍历者
2、Message:消息
3、MessageQueue:队列消息
4、Hanlder:消息的发起者、接受者
我们从Handler通信之前三步骤入手进行总结:
一、Looper.prepare()
Ctrl + 鼠标左键 查看源码
可以看到一个线程中只能存在一个Looper对象,如果有多个的话就会抛异常,继续点击进去查看Looper构造函数都干了啥
此方法里面创建了一个消息队列,并将当前线程赋值给mThread,结合上面的Looper.prepare()方法可以看出 消息队列(MessageQueue)也只能存在一个。
总结
Looper.prepare()的作用
1、创建Looper对象
2、创建MessageQueue对象
3、获取当前线程
二、Handler()
同样我们Ctrl + 鼠标左键查看Handler的构造函数都干了啥
我们可以看到在构造方法中 Handler 获取到了 Looper对象 和MessageQueue,在源码中看到没有创建Looper对象会抛出异常,所以子线程中必须通过Looper.prepare()方法来获取Looper对象,否则Handler是没办法发送和接收消息的。
总结
Handler()
1、得到Handler对象
2、获取Looper和Message对象
三、Looper.loop()
常规操作,Ctrl + 鼠标左键,查看该方法干了啥
同样的它也是获取Looper对象 和MessageQueue,最后我们看这个for循环,这是一个无限循环,我们通过Message msg = queue.next()可以看出,可以看出for循环的作用是从消息队列里获取消息的,在创建Handler时都会重写一个handleMessage方法来接收消息,现在我们只要找到这个方法今天的总结就结束了。不买官司了就在我们的For循环中
msg.target.dispatchMessage(msg);
到此Handler分发机制总结完毕,感谢您的阅读。动动你的手点个赞呗!!!