持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情
数量关系
Looper.prepare()将Looper存储到ThreadLocal中,保证一个线程只有一个Looper,MessageQuene又是在Looper的构造方法中进行的初始化,而Handler是开发人员自己实例化的可以创建多个。所以一个线程一个Looper一个MessageQuene多个Handler
主线程和子线程使用区别
主线程为什么不用进行Looper.prepare()和Looper.loop()方法的调用就可以使用Hnadler。而其他子线程需要调用上述两个方法才能使用Handler。
app入口类ActivityThread的main()中就已经调用了Looper.prepareMainLooper()和Looper.loop()两个方法。所以主线程也要调用只不过ActivityThread帮你做了
大概流程
Looper中for(;;)死循环调用MessageQuene的next()方法(该方法也为for(;;)死循环)取出最新消息。取出消息后调用dispatchMessage()进行message的分发。Message中有target存储Handler所以可以回调给不同的hanlder。
Handler中的延时消息
Message中通过when来记录message执行的时间点。延时消息就是通过加上延长的时间来实现。
Handler中的同步屏障
插入了一个target为null的消息。Handler通过mAsynchronous来设置发送的是否为同步消息,创建Handler的时候可以传入boolean值修改。MessageQuene中取消息时会判断target是否为空(同步屏障消息),如果为空去取下一个消息:如果为同步消息不发送,异步消息才进行发送
主线程如何在for(;;)情况实现不阻塞主线程
MessageQuene中没有消息会调用nativePollOnce进行阻塞用于标识当前无消息,当有消息进入队列时会调用nativeWake进行唤醒队列。
其实只是Java层的Mq没有消息,Native里面也有Mq和Looper,例如接收底层点击事件通过单独的一个InputQuene队列,Native层的消息处理是比Java的优先级高的,所以Java发送Message的时候很长时间没有收到回调是因为Native的Mq紧张
nativePollOnce,nativeWale实现类似于linux的epoll机制。监视文件描述符中的 IO 事件.nativePollOnce
具体链接:www.kancloud.cn/alex_wsc/an…
Hnadler内存泄漏
匿名内部类会默认持有外部类的引用,而创建Handler如果为匿名内部类的话会有内存泄漏的隐患:Handler拿着Activity的引用,Message中target属性拿着Handler的引用,MessageQuene又拿着Message的引用。如果此时销毁activity的时候还有消息没有处理完则会导致内存泄漏。
处理方法:在销毁Activity的时候进行 消息队列的清空