在其 next()方法中会无限循环,不断判断是否有消息,
有就返回这条消息并移除。
- Handler(消息处理器): 负责 Message 的发送及处
理。主要向消息池发送各种消息事件
(Handler.sendMessage()
)和处理相应消息事件
(Handler.handleMessage()
),按照先进先出执行,
内部使用的是单链表的结构。 Looper
(消息池): 负责关联线程以及消息的分发,在
该线程下从MessageQueue
获取 Message,分发给Handler,Looper 创建的时候会创建一个MessageQueue
,调用loop()
方法的时候消息循环开始,其中会不断调用messageQueue
的 next()方法,当有消息就处理,否则阻塞在messageQueue
的next()方法中。当Looper
的quit()
被调用的时候会调用
messageQueue
的quit()
,此时next()
会返回 null,然
后loop()
方法也就跟着退出。
具体流程如下:
- 在主线程创建的时候会创建一个
Looper
,同时也会在在
Looper
内部创建一个消息队列。而在创键 Handler 的
时候取出当前线程的Looper
,并通过该Looper
对象获
得消息队列,然后 Handler 在子线程中通过MessageQueue.enqueueMessage
在消息队列中添
加一条 Message - 通过
Looper.loop()
开启消息循环不断轮询调用
MessageQueue.next()
,取得对应的 Message 并且
通过Handler.dispatchMessage
传递给 Handler,最
终调用Handler.handlerMessage
处理消息。
2、一个线程能否创建多个 Handler,Handler 跟 Looper 之间的对应关系 ?
- 一个 Thread 只能有一个
Looper
,一个MessageQueen
,可以有多个 Handler - 以一个线程为基准,他们的数量级关系是:
Thread(1)
:
Looper(1)
:MessageQueue(1)
:Handler(N)
3、软引用跟弱引用的区别
- 软引用(
SoftReference
): 如果一个对象只具有软引用,则
内存空间充足时,垃圾回收器就不会回收它;如果内存空间不
足了,就会回收这些对象的内存。只要垃圾回收器没有回收
它,该对象就可以一直被程序使用。 - 弱引用(
WeakReference
): 如果一个对象只具有弱引用,那
么在垃圾回收器线程扫描的过程中,一旦发现了只具有弱引用
的对象,不管当前内存空间足够与否,都会回收它的内存。 - 两者之间根本区别在于: 只具有弱引用的对象拥有更短暂的生
命周期,可能随时被回收。而只具有软引用的对象只有当内存
不够的时候才被回收,在内存足够的时候,通常不被回收
4、Handler 引起的内存泄露原因以及最佳解决方案
为什么会导致泄露:
Handler 允许我们发送延时消息,如果在延时期间用户
关闭了 Activity,那么该 Activity 会泄露。 这个泄露
是因为 Message 会持有 Handler,而又因为 Java 的
特性,内部类会持有外部类,使得 Activity 会被
Handler 持有,这样最终就导致 Activity 泄露。
怎么解决:
将 Handler 定义成静态的内部类,在内部持有
Activity 的弱引用,并在 Acitivity
的 onDestroy()
中
调用 handler.removeCallbacksAndMessages(null)
及时移除所有消息。
5、为什么系统不建议在子线程访问 UI?
Android 的 UI 控件不是线程安全的,如果在多线程中并发访问
可能会导致 UI 控件处于不可预期的状态
这时你可能会问为何系统不对 UI 控件的访问加上锁机制呢?因为:
- 加锁机制会让 UI 访问逻辑变的复杂
- 加锁机制会降低
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
UI 的访问效率,因为加锁会阻塞某些线
程的执行
6、Looper 死循环为什么不会导致应用卡死?
- 主线程的主要方法就是消息循环,一旦退出消息循环,那么你的应用也就退出了,
Looer.loop()
方法可能会引起主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理事件就不
会产生 ANR 异常。 - 造成
ANR
的不是主线程阻塞,而是主线程的Looper
消息处理过程发生了任务阻塞,无法响应手势操作,不能及时刷新 UI。 - 阻塞与程序无响应没有必然关系,虽然主线程在没有消息可处理的时候是阻塞的,但是只要保证有消息的时候能够立刻处
理,程序是不会无响应的。
7、使用 Handler 的 postDealy 后消息队列会有什么变化?
如果队列中只有这个消息,那么消息不会被发送,而是计算到
时唤醒的时间,先将 Looper
阻塞,到时间就唤醒它。但如果此时要加入新消息,该消息队列的对头跟 delay 时间相比更长,
则插入到头部,按照触发时间进行排序,队头的时间最小、队
尾的时间最大
8丶子线程直接 new 一个 Handler 吗?怎么做?
不可以,因为在主线程中,Activity 内部包含一个 Looper 对
象,它会自动管理 Looper
,处理子线程中发送过来的消息。而
对于子线程而言,没有任何对象帮助我们维护 Looper
对象,所以需要我们自己手动维护。所以要在子线程开启 Handler 要先
创建 Looper
,并开启 Looper
循环
9、Message 可以如何创建?哪种效果更好,为什么?
可以通过三种方法创建:
- 直接生成实例
Message m = new Message
- 通过
Message m = Message.obtain
为什么?
可以通过三种方法创建: - 直接生成实例
Message m = new Message
- 通过
Message m = Message.obtain