当前位置: 首页 > news >正文

安卓基础组件Looper - 01 通讯机制简介

文章目录

  • 为什么需要 Looper
  • 成员
    • MessageQueue
    • Looper
    • Handler lambda
  • 机制图

为什么需要 Looper

main函数/普通函数执行完后,整个进程/线程也就结束了。为了让处理可执行对象的进程/线程长时间运行,需要无限循环加事件通知的机制

int main()
{
    while(true)
    {
        1. 线程进入休眠状态,等待通知;
        2. 其它地方给当前线程发送通知,线程从休眠中唤醒,读取通知,处理通知
        3. 进入下一个循环
    }

    return 0;
}

成员

MessageQueue

MessageQueue:装message的容器。

  • 使用 pool 享元设计模式。

  • 有消息处理,数量不能过多。pool会超出容量。

  • 根据时间排序,

    • message queue队列满的时候,阻塞,直到用户通过next取出消息。

    • 当出队 next方法 被调用,通知MessagQueue可以进行消息的入队。

    // frameworks/base/core/java/android/os/MessageQueue.java
        boolean enqueueMessage(Message msg, long when) {
    

生产者消费者

  • 入队 生产者:子线程 向消息队列添加消息和Handler

  • 出队 消费者工作线程:工作线程依此轮循,轮询到了MSG就会执行

    • java 执行了Looper.loop() 的线程(往往是主线程。因此MSG的消费,执行,都在主线程中)
    • cpp Looper::prepare/new Looper的线程

数量关系:(有说法是每个进程只有一个MessageQueue。但我看起来是觉得每个工作线程都有且只有一个MessageQueue)

  • java

    // frameworks/base/core/java/android/os/Looper.java
    
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
    
    // sThreadLocal.get() will return null unless you've called prepare().
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
  • native

    class Looper : public RefBase {
        Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
    

Looper

在线程(一般是主线程)中执行Looper.loop(),则这个线程就是“工作线程”。可以认为是MSG的消费者:所有的MSG的消费,执行都是在该线程中。

  • 调用了 Looper::loop() 的线程,会从进程的MessageQueue中取出、处理MSG,并执行Hanlder的重载。

  • 因为 MessageQueue 是线程安全的,所以可以有多个线程调用 Looper::loop(),这些线程并行的处理Hanlder。

对于app来说,这个“工作线程”就是主线程。app启动/挂断,一定是从主线程的 main函数 开始的

// frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
    // 准备loop
    Looper.prepareMainLooper();
    Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
    // 让loop运行起来. 一直循环,保障进程一直执行,如果退出,说明程序关闭
    Looper.loop();

数量关系:进程中可以在进程中指定一个/多个工作线程,每个工作线程拥有一个Looper

  • 一个线程只允许有一套Handler通讯机制,只有一个Looper

    在native层 一个线程new多个Looper是不建议的,但神奇的是这往往并不会出错,符合能跑就行的思想。

  • 一个进程可以有多个工作线程,从而一个进程中可有多个Looper

Handler lambda

狭义的来说

  • Handler是一个类,一个线程有多个 Handler对象 ——设计模式命令模式
  • 定义 Handler时,需要指定 Looper 意味着于此同时确定了对应的MessageQueue和工作线程。
  • 各个线程怎么区分其中的msg该让哪个Handler执行呢?
    • Handler.sendMessage时会把this(也就是哪个Handler)传递给MessageQueue。
    • 所以,才能让对应 Handler 执行其 handleMessage方法

广义来说:Handler是一种线程通信的方案。

  • 作为方案,MessageQueue和Looper也包含其中

  • 实际上是内存共享的方案

    • MessageQueue这个容器 在同一进程中的线程间是 共享 的,

    • 主线程可以通过loop死循环去不断的访问 MessageQueue。

为什么 wait/notify用处不大:因为handler已经将需要这部分功能进行了Linux层的封装 使用epoll多路IO复用进行管理。

机制图

解决线程之间的通讯:(并不跨进程)

其他跨线程通信:retrofit,eventbus,rxjava都是使用了主线程MainThread的,底层都使用了Handler机制(Looper机制)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

相关文章:

  • 【实战 ES】实战 Elasticsearch:快速上手与深度实践-2.1.3时间序列数据优化(Rollover + ILM策略)
  • Leetcode 30. 串联所有单词的子串
  • 小鹏汽车申请注册“P7 Ultra”商标 或为P7车型升级版铺路
  • [java基础知识] java的集合体系Collection(List,Set,Queue),Map
  • 基于python跨平台硬件诊断的工具
  • 刷题 | 牛客 - js入门15题(更ing)5/15知识点解答
  • ubuntu 启动不起来,光标闪烁 解决方法
  • 杰和科技工业整机AF208|防尘+静音+全天候运行
  • GPU/CUDA 发展编年史:从 3D 渲染到 AI 大模型时代
  • 谈谈 HTTPS 的工作原理,SSL / TLS 握手流程是什么?
  • RabbitMQ怎么实现延时支付?
  • C++:内联函数
  • Linux常用指令
  • VirtualBox虚拟机安装Mac OS启动后的系统设置
  • 指纹细节提取(Matlab实现)
  • Java 大视界 -- Java 大数据在智能教育考试评估与学情分析中的应用(112)
  • RV1126的OSD模块和SDL_TTF结合输出H264文件
  • Elasticsearch简单学习
  • 电子电路中,正负双电源供电的需求原因
  • excel 斜向拆分单元格
  • 公司网站介绍模板 html/青海seo技术培训
  • 网站建设文化传播有限公司/如何成为app推广代理
  • 专业网站设计制作过程/百度推广获客方法
  • vps怎么搭建网站/独立站谷歌seo
  • 多语言网站源码/外贸企业网站制作哪家好
  • 有知道做网站的吗/最近有哪些新闻