1、线程和looper绑定?
使用Looper.prepare ,基于线程的ThreadLocal 在prepare时new Loop
2、如何保证一个线程只有一个looper?
一个线程就只有一个looper了,因为如果执行一遍线程运行 Looper.prepare() 后,线程中有looper了,再次执行这个方法,直接会抛异常,这样canLooper就会为false了,接下来往下走就不会执行Looper.loop()了。
3、Handler内存泄露原因?其他内部类为什么没有这个问题?
内部类虽然和外部类写在同一个文件中,但是编译后还是会生成不同的class
文件,其中内部类的构造函数中会传入外部类的实例,然后就可以通过this$0
访问外部类的成员。
第一种情况,是通过handler
发送延迟消息,核心问题是主线间接引用到了activity没有释放,主线程 —> threadlocal —> Looper —> MessageQueue —> Message —> Handler —> Activity
第二种情况:由于子线程这个匿名内部类持有了外部类的引用,而子线程本身是一直在运行的,刚才说过运行中的线程是不会被回收的,所以这里内存泄漏的引用链应该是:运行中的子线程 —> Activity,当然,这里的Handler也是持有了Activity的引用的,但主要引起内存泄漏的原因还是在于子线程本身,就算子线程中不用Handler,而是调用Activity的其他变量或者方法还是会发生内存泄漏。
4、为啥主线程可以new Handler?其他子线程可以吗?
主线程已经创建了 Looper 对象并开启了消息循环,其他子线程可以,但必须Looper.pearer绑定loop
5、子线程维护的looper 没有消息是是怎么处理的?
queue.next()会一直等待,这个时候就会block住,换句话说,这里block住,意味着Lopper一直在这里面等待,run函数一直处于等待状态,run会一直被执行,线程不会销毁,结果内存泄漏,线程一直处于执行状态,所以这时候,我们线程所有的上下文全部都会在内存当中,那么这样自会导致CPU浪费,内存浪费
解决办法:
在Looper里面有一个quite(),会调用nativeWake,nativePollOnce是出于等待,nativeWake是唤醒,唤醒之后往下面执行,最后next返回null,loop循环就会退出,Looper就推出,run方法往下执行,接着就会释放内存,把CPU交出去,给别人用。
6、Looper的死循环为什么不会导致卡死?
Looper的死循环就是为处理主线程的消息,主线程的呈现就是looper的结果
7、Handler 的postDelay后的消息队列怎么变化?
- 1.消息是通过MessageQueen中的enqueueMessage()方法加入消息队列中的,并且它在放入中就进行好排序,链表头的延迟时间小,尾部延迟时间最大
- 2.Looper.loop()通过MessageQueue中的next()去取消息
- 3.next()中如果当前链表头部消息是延迟消息,则根据延迟时间进行消息队列会阻塞,不返回给Looper message,直到时间到了,返回给message
- 4.如果在阻塞中有新的消息插入到链表头部则唤醒线程
- 5.Looper将新消息交给回调给handler中的handleMessage后,继续调用MessageQueen的next()方法,如果刚刚的延迟消息还是时间未到,则计算时间继续阻塞
8、消息队列的消息由多个handler发送,怎么保证线程安全?
通过synchronized来保证了线程的安全性
9、MessageQueue的quit和quitSafely 的区别
removeAllFutureMessagesLocked是会等延时消息进行时间判断符合超时去删除 removeAllMessagesLocked 直接清理message