Android面试——Handler篇

一: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机制中的作用

 

上一篇:在Windows下安装C与C++环境


下一篇:深度学习之模型量化