对于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()
主要涉及到四个类 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分发机制总结完毕,感谢您的阅读。动动你的手点个赞呗!!!
