一:Handler的实现原理
Handler:负责发送消息和处理消息
Message:消息对象
MessageQueue:消息队列,存放消息对象
Looper:消息队列的处理者,轮询消息队列中的消息对象
过程:
Handler发送消息时调用MessageQueue的enqueueMessage插入一条信息到MessageQueue,Looper不断轮询调用MeaasgaQueue的next方法 如果发现message就调用handler的dispatchMessage,dispatchMessage被成功调用,接着调用handlerMessage()。
二:主线程可以直接new Handler,而子线程不可以的原因?
Handler的构造方法中会通过Looper的静态方法myLooper()获取Looper对象,如果为空则报异常;
主线程由于在ActivityThread的main方法中,通过Looper.prepareMainLooper()获取到这个对象,并通过Looper.loop()开启循环;
子线程可以通过Looper.prepare()获取到looper,并使用Looper.loop()开启循环;
三:一个线程可以有几个looper,几个handler,几个Message Queue?
一个线程可以有多个Handler,只有一个Looper对象,只有一个MessageQueue对象;
创建的Looper对象会放在当前线程ThreadLocal中,ThreadLocal类中维护了ThreadLocalMap类,该类以当前Thread作为key,
Looper的构造方法中创建了MessageQueue对象,并赋值给mQueue,因此该对象也只有一个;
四:Handler 导致的内存泄露原因以及解决方案
原因:使用非静态内部类的方式创建Handler;
解决方案:子类handler设置成静态,使用弱引用持有Activity实例;当外部类结束生命周期时,清空handler的消息队列
五:Message对象的创建方式有哪些,以及区别
1. new 一个Message对象,这样每次都要到堆空间开辟空间
2. Message.obtain() 先判断消息池是否为空,非空则将表头的Message取走,再将指针指向next,如果为空,则将new 一个,放进去,消息池最大为50,消息在被分发消费后会执行回收的操作,将消息内部数据清空添加到消息链表的表头
3. handler.obtainMessage(),内部也是调用的方法2
六:handler 有哪些发送消息的方法
sendMessage(Message msg)
sendMessageDelayed(Message msg, long uptimeMillis)
post(Runnable r)
postDelayed(Runnable r, long uptimeMillis)
sendMessageAtTime(Message msg,long when)
七:handler 的post和sendMessage的区别和使用场景
post方法和handleMessage方法的不同在于,区别就是调用post方法的消息是在post传递的Runnable对象的run方法中处理,而调用sendMessage方法需要重写handleMessage方法或者给handler设置callback,在callback的handleMessage中处理并返回true
应用:
post一般用于单个场景 比如单一的倒计时弹框功能
sendMessage的回调需要去实现handleMessage Message则做为参数 用于多判断条件的场景。
八:postDelay后消息队列有什么变化?
postDelayed传入的时间,会和当前的时间SystemClock.uptimeMillis()做加和,
延时消息会和当前消息队列里的消息头的执行时间做对比,如果比头的时间靠前,则会做为新的消息头,不然则会从消息头开始向后遍历,找到合适的位置插入延时消息
postDelay()一个10秒钟的Runnable A、消息进队,MessageQueue调用nativePollOnce()阻塞,Looper阻塞;
紧接着post()一个Runnable B、消息进队,判断现在A时间还没到、正在阻塞,把B插入消息队列的头部(A的前面),然后调用nativeWake()方法唤醒线程;
MessageQueue.next()方法被唤醒后,重新开始读取消息链表,第一个消息B无延时,直接返回给Looper;
Looper处理完这个消息再次调用next()方法,MessageQueue继续读取消息链表,第二个消息A还没到时间,计算一下剩余时间(假如还剩9秒)继续调用nativePollOnce()阻塞; 直到阻塞时间到或者下一次有Message进队;
九:MessageQueue是什么数据结构?
内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息列表 这点和传统的队列有点不一样,
主要区别在于Android的这个队列中的消息是按照时间先后顺序来存储的,时间较早的消息,越靠近队头。 当然,我
们也可以理解成,它是先进先出的,只是这里的先依据的不是谁先入队,而是消息待发送的时间
十:ThreadLocal在Handler机制中的作用