2.子线程中能不能直接new一个Handler,为什么主线程可以 主线程的Looper第一次调用loop方法,什么时候,哪个类
不能,因为Handler
的构造方法中,会通过
Looper.myLooper()
获取
looper
对象,如果为空,则抛出异常, 主线程则因为已在入口处ActivityThread
的
main
方法中通过
Looper.prepareMainLooper()
获取到这个对象, 并通过 Looper.loop()
开启循环,在子线程中若要使用
handler
,可先通过
Loop.prepare
获取到
looper
对象,并使用 Looper.loop()开启循环。
3.Handler导致的内存泄露原因及其解决方案
1.Java
中非静态内部类和匿名内部类都会隐式持有当前类的外部引用
2.
我们在
Activity
中使用非静态内部类初始化了一个
Handler,
此
Handler
就会持有当前
Activity
的引用。
3.
我们想要一个对象被回收,那么前提它不被任何其它对象持有引用,所以当我们
Activity
页面关闭之后
,
存在引用关 系:"
未被处理
/
正处理的消息
-> Handler
实例
->
外部类
",
如果在
Handler
消息队列 还有未处理的消息
/
正在处理消 息时 导致Activity
不会被回收,从而造成内存泄漏
解决方案
:
1.
将
Handler
的子类设置成 静态内部类
,
使用 WeakReference弱引用持有
Activity
实例
2.
当外部类结束生命周期时,清空
Handler
内消息队列
4.一个线程可以有几个Handler,几个Looper,几个MessageQueue对象
一个线程可以有多个Handler,
只有一个
Looper
对象
,
只有一个
MessageQueue
对象。
Looper.prepare()
函数中知道,。在Looper
的
prepare
方法中创建了
Looper
对象,并放入到
ThreadLocal
中,并通过
ThreadLocal
来获取
looper 的对象, ThreadLocal
的内部维护了一个
ThreadLocalMap
类
,ThreadLocalMap
是以当前
thread
做为
key
的
,
因此可以得 知,一个线程最多只能有一个Looper
对象, 在
Looper
的构造方法中创建了
MessageQueue
对象,并赋值给
mQueue
字段。因为
Looper
对象只有一个,那么
Messagequeue
对象肯定只有一个。
5.Message对象创建的方式有哪些 & 区别,Message.obtain()怎么维护消息池的
1.Message msg = new Message();
每次需要
Message
对象的时候都创建一个新的对象,每次都要去堆内存开辟对象存储空间
2.Message msg = Message.obtain();
obtainMessage
能避免重复
Message
创建对象。它先判断消息池是不是为空,如果非空的话就从消息池表头的 Message取走
,
再把表头指向
next
。
如果消息池为空的话说明还没有
Message
被放进去,那么就
new
出来一个
Message
对象。消息池使用
Message
链表 结构实现,消息池默认最大值 50
。消息在
loop
中被
handler
分发消费之后会执行回收的操作,将该消息内部数据清空
并添加到消息链表的表头。
3.Message msg = handler.obtainMessage();
其内部也是调用的
obtain()
方法
6.Handler 有哪些发送消息的方法
sendMessage(Message msg)
sendMessageDelayed(Message msg, long uptimeMillis)
post(Runnable r)
postDelayed(Runnable r, long uptimeMillis)
sendMessageAtTime(Message msg,long when)
7.Handler的post与sendMessage的区别和应用场景
1.
源码
sendMessage
sendMessage-sendMessageAtTime-enqueueMessage
。
post
sendMessage-getPostMessage-sendMessageAtTime-enqueueMessage getPostMessage
会先生成一个 Messgae,并且把
runnable
赋值给
message
的
callback
2.Looper->dispatchMessage
处理时
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
if (mCallback.handleMessage(msg)) {
dispatchMessage
方法中直接执行
post
中的
runnable
方法。
而
sendMessage
中如果
mCallback
不为
null
就会调用
mCallback.handleMessage(msg)
方法,如果
handler
内的 callback不为空,执行
mCallback.handleMessage(msg)
这个处理消息并判断返回是否为
true
,如果返回
true
,消息 处理结束,如果返回false,handleMessage(msg)
处理。否则会直接调用
handleMessage
方法。
post方法和
handleMessage
方法的不同在于,区别就是调用
post
方法的消息是在
post
传递的
Runnable
对象的
run
方法中处理,而调用sendMessage
方法需要重写
handleMessage
方法或者给
handler
设置
callback
,在
callback
的
handleMessage
中处理并返回
true
应用场景
post
一般用于单个场景 比如单一的倒计时弹框功能
sendMessage
的回调需要去实现
handleMessage Message
则做为参数 用于多判断条件的场景。
8.handler postDealy后消息队列有什么变化,假设先 postDelay 10s, 再 postDelay 1s, 怎么处理这2条消息sendMessageDelayed-sendMessageAtTime-sendMessage