Handler相关
Q:说说Handler机制?
Handler机制涉及三个对象:
- Handler
- Looper:负责不断从 MessageQueue 中取出 Message,然后处理 Message 中指定的任务。
- MessageQueue
通过Handler进行线程通信的流程是:
- new Handler,在这一步会去获取当前线程的Looper
- 通过handler进行send一个消息,这一步,会把消息加入到Looper的队列中,并根据时间进行排序
Q:为什么Looper.loop()不会阻塞主线程?
在MessageQueue的next方法中:
nativePollOnce 方法是一个 native 方法,当调用此 native 方法时,主线程会释放 CPU 资源进入休眠状态,直到下条消息到达或者有事务发生,通过往 pipe 管道写端写入数据来唤醒主线程工作,这里采用的 epoll 机制。
Q: Handler 的 sendMessageDelayed 或者 postDelayed 是如何实现的?
从next()源码可以看出,当取出下一条消息的时候,如果当前时间小于msg.when,就会计算一个timeout,把这个timeout的时间传递给nativePollOnce,系统就会定时把CPU唤醒。
但是,从代码逻辑也看出,这个delay是不精准的,它只能保证不会在when之前被处理,不能保证一定在when时刻被处理。
Q:为什么在子线程发送消息需要Looper.prepare()
因为发送消息需要Looper的支持,但是在子线程是默认没有初始化Looper的,所以需要我们手动调用Looper.prepare()初始化。
调用Looper.prepare()的时候,会把Looper保存到ThreadLocal中,ThreadLocal有一个特点就是每一个线程独一份数据。
至于主线程为什么不用,是因为应用启动的时候会调用ActivityThread.main()方法,在这个方法里会调用Looper.prepareMainLooper()初始化Looper。
到这里其实原理就差不多了,但是还可以扩充一个内容,那就是用基于实现捕获主线程所有异常。
Q:Looper的妙用
Looper可以用来捕获UI线程异常,用于ANR检测等; 比如:捕获全局UI线程异常:
val handler = Handler(Looper.getMainLooper())
handler.post {
while (true) {
try {
Looper.loop()
} catch (e: Throwable) {
// TODO 主线程崩溃,自行上报崩溃信息
if (e.message != null && e.message!!.startsWith("Unable to start activity")) {
android.os.Process.killProcess(android.os.Process.myPid())
break
}
e.printStackTrace()
}
}
}