讲讲Handler实现原理

本文解析了Handler、Looper、MessageQueue等关键组件的工作原理及其在消息传递中的作用,深入探讨了消息队列的初始化过程和消息分发流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

各主要类作用:

Handler:负责发送消息及处理消息
Looper:复制不断的从消息队列中取出消息,并且给发送本条消息的Handler
MessageQueue:负责存储消息
Message:消息本身,负责携带数据

分发流程:

初始化消息队列,创建messageQueue并绑定到Looper上。

Handler的sendMessage发起消息处理流程开端,创建Message并放入到MessageQueue中,由Looper的无限循环任务唤醒阻塞,开始分发Message,执行Message的Runable之后,调用保存的handler的handleMessage方法,回到handler实现结束消息流程。

 

主要类的关联关系:

ThreadLocal中获取Looper对象,说明Looper是线程独立的,即主线程(MainThread)持有。

MessageQueue是在Looper的构造方法创建,说明Looper是关联的MessageQueue的。采用next持有message对象引用,形成链表实现。

Looper的loop方法,发起for(;;)无限循环,在message.next()中或者没有对象阻塞,或者有对象进行message执行。

Message中callback保存runable对象用来执行,next保存下一个message用来实现链表,target用来执行runable的run方法。

 

延申问题:

那么,loop的for(;;)会阻塞线程,那么主线程是如何在阻塞时接触阻塞的呢?按上面的说法是没有其他线程进行唤醒操作的

如果你了解下linux的epoll你就知道为什么不会被卡住了,先说结论:阻塞是有的,但是不会卡住 
主要原因有2个

  1. epoll模型 
    当没有消息的时候会epoll.wait,等待句柄写的时候再唤醒,这个时候其实是阻塞的。

  2. 所有的ui操作都通过handler来发消息操作。 
    比如屏幕刷新16ms一个消息,你的各种点击事件,所以就会有句柄写操作,唤醒上文的wait操作,所以不会被卡死了。

在代码ActivityThread.main()中:
public static void main(String[] args) {
        .... 
        //创建Looper和MessageQueue对象,用于处理主线程的消息
        Looper.prepareMainLooper(); 
        //创建ActivityThread对象
        ActivityThread thread = new ActivityThread();  
        //建立Binder通道 (创建新线程)
        thread.attach(false); 
        Looper.loop(); //消息循环运行
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

thread.attach(false);便会创建一个Binder线程(具体是指ApplicationThread,Binder的服务端,用于接收系统服务AMS发送来的事件),该Binder线程通过Handler将Message发送给主线程,具体过程可查看 startService流程分析,这里不展开说,简单说Binder用于进程间通信,采用C/S架构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值