系列文章
Activity总结和补充
Android Binder&Aidl理解和补充
Handler总结和补充
<Service史上最全面解析>理解和补充
四大组件总结
目录
![](https://i-blog.csdnimg.cn/blog_migrate/289c8a11ba3889490a8498abe33b85e2.png)
1. 定义
一套 Android
消息传递机制
2. 作用
在单线程的应用场景中,用于线程内部通信(sendmessage-->handlemessage)
在多线程的应用场景中,将工作线程中需更新UI
的操作信息 传递到 UI
主线程,从而实现 工作线程对UI
的更新处理,最终实现异步消息的处理。
Handler不是多线程,是一种发送接收机制.
Handler用于线程通信,binder用于进程通信.
3 适用场景
Android界面和业务逻辑分离:只有主线程(UI线程)更新界面,工作线程处理业务逻辑.在子线程中画图是不行的.
所以Android经常使用handler机制实现主线程和子线程通信。
4 Handler实例分析
先有个感性认识. mainThread中ActivityThread创建了一个运行在主线程的Looper,并且把它和主线程进行了绑定。
public final class ActivityThread {
public static final void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
......
Looper.loop();
......
}
}
Handler实例分析 https://blog.csdn.net/fdsafwagdagadg6576/article/details/117226751
5 工作原理(设计)
整体结构
5.1 角色作用(拆解模块分工)
handler机制由4个module组成:handler,looper, msgqueue,msg.
1) 各个模块作用: handler,looper, msgqueue,msg
上图就是整个Handler
在Java层的流程示意图。在Handler
调用sendMessage
方法以后,Message
对象会被添加到MessageQueue
中去。而这个MessageQueue
就是被包裹在了Looper
中。那么Looper
对象是干什么的呢?它和Handler
是什么关系呢?我们来看一下他们具体的职责把~.
-
Handle
消息机制中作为一个对外暴露的工具(对外接口),其内部包含了一个Looper(默认或者通过构造函数绑定)
。2个作用:Message
的发送及处理.Handler.sendMessage()
:向消息队列发送各种消息事件Handler.handleMessage()
:处理相应的消息事件
-
Looper
作为消息循环的核心,其内部包含了一个消息队列MessageQueue
,用于记录所有待处理的消息;通过Looper.loop()
不断地从MessageQueue
中抽取Message
,按分发机制将消息分发给目标处理者,可以看成是消息泵。注意,线程切换就是在这一步完成的。
在handler应用层没有looper创建和运行的代码,looper的创建在ActivityThread即main函数中,looper运行是android做的.
2个作用:msg读取和分发. -
MessageQueue
则作为一个消息队列,则包含了一系列链接在一起的Message
;不要被这个Queue的名字给迷惑了,就以为它是一个队列,但其实内部通过单链表的数据结构来维护消息列表,等待Looper
的抽取。
1个作用: queue用于存取数据.有queue一定涉及多线程.
notes: 多线程场景,两个线程一个放一个取.
-
Message
则是消息体,内部又包含了一个目标处理器target
,这个target
正是最终处理它的Handler
小结:
角色 | 作用 | 分层(activity入口--开发者使用--android系统层) |
handler | 发送和处理消息 | 开发者使用接口. |
looper | 每个线程只能有一个Looper。messageQueue属于它. 它的loop方法负责读取MessageQueue中的消息,读到消息后把消息发送给Handler进行处理。| (线程和Looper绑定) | Activity入口函数创建&android 系统层使用 |
messagequeue | 先进先出的方式来管理msg.创建Looper对象时,会在它的构造方法中创建MessageQueue对象。(looper和messagequeue绑定) | android 系统层使用 |
message | 消息 | 应用层 |
要点:一个Activity1 ⇔线程 ⇔ 1 Looper ⇔ 1 MessageQueue ⇔ n Handler(绑定handlemessage) ⇔ m Message ;
5.2 消息流程:
Message -> Handler ( 发送sendmessage ) -> MessageQueue ( 存储 ) -> Looper ( 轮询 ) -> Handler ( 执行handlemessage )
- 总体流程
- Handler通过sendMessage()发送Message到MessageQueue队列;
- Looper通过loop(),不断提取出达到触发条件的Message,并将Message交给target来处理;
- 经过dispatchMessage()后,交回给Handler的handleMessage()来进行相应地处理。
- 将Message加入MessageQueue时,往管道写入字符,可以会唤醒loop线程;
发送-接收-分发-处理
handler sendmessage-->looper轮询读取和分发-->handler的回调处理.
5.3 Handler在多线程中使用(生产者消费者模型)
多-1-多模型.
模块 | 线程 |
生产者 | 子线程handler.sendmessage |
消费者 | 主线程 looper & handler.handlemessage |
中介 | 主线程 messageQueue |
5.4 线程同步
线程同步在messageQueue的native层实现.
1) 生产者线程和消费者线程同步:
如果messageQueue为空: messageQueued.next 通过epoll监听messagequeue绑定的文件fd,实现读写同步.
如果messageQueue不为空: 生产者线程写,消费者线程读
2) 多个生产者线程同时写:使用messageQueued.enqueueMessage中的锁同步.
小结:
- 主线程和子线程通信依靠1个全局变量messagequeue。
handler作为全局变量,负责在子线程发送,主线程处理.
looper和messagequeue绑定。使用looper 初始化handler,handler和looper绑定。 - Handler机制和handler+Thread连用的区别:handler不是多线程,在同一个线程中创建,发送和接收,属于handler机制。只有两个线程之间,使用handler发送和接收才是多线程通信. 刷新UI looper必须在主线程创建,不刷新UI只处理消息 looper可以在子线程创建.
Handler可以在一个线程内使用. handler也可以在不同线程内使用. - Handler和looper绑定:创建handler,构造函数要传入Looper。主线程创建handler,默认使用主线程looper,不需要显式传入.
- Handler创建和handlemessage(handler处理)在一个线程.
附:Handler,looper,handlemessage,sendmessage关系图
handler | looper | handlemessage | sendmessage | 使用场景 |
主线程定义&创建 | 主线程或者子线程 | 主线程 | 主线程 | handler机制,是单线程操作,不是多线程,可以UI操作. |
主线程定义&创建 | 主线程或者子线程(thread.looper) | 主线程 | 子线程 | Thread+handler; 线程通信,可以处理UI操作 |
子线程定义&创建 | 子线程(自定义)或者加载主线程looper (getMainLooper) | 子线程 | 子线程 | handler机制,是单线程操作,不能多线程通信,不能处理UI操作. 可以在创建handler的线程内发送,接收消息,仅仅是handler机制不是多线程 |
主线程定义&子线程创建 | 父子都可以 | 子线程 | 主线程 | Thread+hander;线程通信,不可以处理UI操作.因为handler定义是global的 |
6 源码分析
Handler机制源码分析 https://blog.csdn.net/fdsafwagdagadg6576/article/details/111300450
QA:
- handler和binder区别? handler实现机制是线程通信,采用pipe.而binder是进程通信,所以没有用binder.
- handler的Messagequeue与linux的消息队列区别?
linux 消息队列是内存实现的msgsend,msgreceive.
handler消息机制是自定义msg数组实现queue,然后用epoll+管道通信。本质是linux管道.一端向管道写fd文件,一端epoll监听管道然后读取。 - 如果不用handle的话,子线程和主线程如何传递msg呢?
那么需要开发者自己写一个生产者-消费者模型。
c语言版本:N个子线程并行写queue.主线程轮询queue读取msg,根据msgid分发给每个线程的处理函数.
c++/java版本: 在子线程中,对象向queue发送数据。主线程轮询读取msg,根据对象id,将msg分发给各个对象的回调函数handlemsg处理。
如果采用线程池的方式,则将对象放入线程池即可。在线程池中发送。主线程接收.
那么handler如何处理呢?handler实际就是封装好的生产者-消费者模型.handler中的N个工作线程就是N个生产者.一个消费者就是UI主线程. (不同的线程可以使用同一个handler). - Handler内存泄漏详解及其解决方案:https://blog.csdn.net/javazejian/article/details/50839443
小结:
handler使用记得sendmessage+handleMessage(等于receive message)就可以了。
如果使用子线程的looper,增加一个子线程创建looper
参考blog:https://juejin.cn/post/6866015512192876557#heading-5
https://www.jianshu.com/p/02962454adf7.
图文解析 Handler通信机制 的工作原理:https://www.jianshu.com/p/f0b23ee5a922。