Android基础: Handler机制相关

前言

仅用于知识点简介,详细描述建议百度,主要是一些个人的理解总结,可以在面试时来回答,所以并不是很详细,只是总结~ 后续应该会不断更新
Activity、Service、BroatcastReceiver、ContentProvider


1. Handler 的作用

handler 是Android 线程间的消息机制,主要作用是将一个任务切换到指定的线程(构成handler的looper所在的线程)中去执行。

2. handler 的架构

Handler 的运行需要底层的 message queue(消息队列) 和 looper 做支撑

3. handler 原理

3.1 Message queue 消息队列

单链表数据结构,通过 enqueue message 方法插入消息,通过next 方法取出消息

3.2 looper 消息调度者
  1. looper 取消息过程
    1. 如果队列中有消息,判断消息执行时间是否大于当前时间
      1. 如果大于,就调用 nativePollOnce阻塞一段时间,然后取出消息执行
      2. 否则直接执行
    2. 没有消息,一直阻塞,直到下一个消息到来,唤醒线程继续循环
  2. Looper 方法解析
    1. 主线程 - ActivityThread 的main 方法,就是App进程入口,通过Looper.prepareMainLooper 在主线程中存储一个 looper
    2. 在子线程中,我们需要通过 Looper.prepare 在子线程存储一个 looper,再通过 looper.loop 开启一个消息循环
3.3 handler

通过 send 发送消息,实际是忘 looper 的 messagequeue 插入一条消息:
改变 消息的 target 为发他的 handler -> looper 取出消息 -> dispatchmessage 处理消息

4. 主线程的 handler

  1. 主线程中的所有操作都是通过主线程中的Handler处理的,包括Activity的生命周期等
  2. ActivityThread 的 main 方法是 App 程序的入口,在 main 中使用 Looper.prepareMainLooper() 设置 looper,然后创建 ApplicationThread 与 server 的 ApplicationThreadProxy 进行进程通信,然后调用 Looper.loop() 开启消息循环
  3. 生命周期:由系统服务 ActivityManagerService 调用 ApplicationThreadProxy 通过 Binder 给当前 app 进程中的 ApplicationThread 发送 暂停 Activity 或 start create 等动作时,app 进程中的 ApplicationThread 便会在 主线程 的 handler 将这个动作消息插入到主线程的 MessageQueue 中去处理

5. Looper 的死循环对性能的消耗问题

looper 区消息的机制就涉及到 Linux pipe/poll 机制,在 MessageQueue 没有消息时,主线程边阻塞在 loop 的 queue.next 中的 nativePollOnce() 方法,此时主线程变回释放CPU来进入休眠状态,知道下个消息到达时,触发 nativeWake,通过pipe管道唤醒主线程继续工作。所以不会消耗cpu资源

6. Looper.loop() 中的死循环 和 ANR 的区别

  1. Looper.loop() 死循环存在的意义在于循环处理队列的消息,否则在取出一条消息处理后,主线程就退出,而死循环可以让主线程等待下一条消息继续处理,且等待时并不会造成性能的消耗
  2. ANR 的原因则是message Queue 中的一个消息处理时间过程,导致接下来的消息无法处理,用户的操作等无法及时响应,才会出现ANR

7. handler.postDelayed 方法怎么实现的?

经 postDelayed 方法加入到 messageQueue,在加入前会计算出这个消息实际应该执行的时间 (SystemClock.uptimeMillis() + delayMillis,其中SystemClock.uptimeMillis()是开机到现在的时间,不会随用户修改系统时间而改变,然后通过 EnqueueMessage 将message 和执行时间一并添加到 messageQueue,EnqueueMessage 会根据执行时间将 Message 插入到适当的位置,也就是说 MessageQueue 是按照 message.when (执行时间)排序的

8. handler.postDelayed函数延时执行计时是否准确

当上一个消息存在耗时任务的时候,会占用延时任务执行的时机,此时是不准确的。那么如何准确执行延时任务呢,可以开启一个HandlerThread为一个专门的唯一的延时消息服务。

9. 系统是如何保证延时消息精确执行

  1. 从 Looper 取消息的方式来看
    1. 如果当前没有消息,那么会插入到队首,在时间到达 message.when 时,就会开始执行消息
    2. 如果当前有消息,那么也会通过死循环,在时间到达 message.when 时,取出消息执行
  2. 从加入一条新的消息来看
    1. postDelayed 会计算实际执行时间,EnqueueMessage 会将message 根据 实际执行时间插入到适当的位置
  • 而这两个动作都是没有延迟的,所以可以保证消息的精确执行

10. ThreadLocal

ThreadLocal 可以在多个线程内存储数据,使用ThreadLocal 存储的数据在多个线程间是隔离的,因为它是将数据存储在每个线程内的 ThreadLocalMap

11. 同步屏障、同步消息、异步消息

  1. 同步消息:就是我们平常发送的消息
  2. 异步消息:一般是系统发送的消息
  3. 同步屏障:就是给消息队列发送了一个屏障信息,消息队列在处理到这个屏障信息时就开启了“同步屏障”模式
    1. 在该模式下,只返回异步消息给Looper处理,屏蔽同步消息。
    2. 在处理异步消息队列后,计时消息队列还有同步消息也会通过nativePollOnce() 进入线程阻塞,直到有新的异步消息进入 或 解除同步屏障模式,同步消息才能得到处理。
    3. 主要是告知系统优先处理此消息,在系统的 invalid 等UI刷新的方法中,就可以看到 MEssage 设置 为 异步消息,来保证优先执行最高优先级
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

俺不理解

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值