Handler总结和补充

系列文章

Activity总结和补充
Android Binder&Aidl理解和补充
Handler总结和补充
<Service史上最全面解析>理解和补充
四大组件总结

目录

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关系图

handlerlooperhandlemessagesendmessage使用场景
主线程定义&创建主线程或者子线程主线程主线程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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值