Handler机制原理学历及相关面试题解析

Handler的机制原理

基本元素:

Handler:在哪个线程创建,就跟哪个线程的Looper关联,也可以在构造方法传入指定Looper;

Looper:一个线程拥有一个looper,通过looper.loop方法轮询MessageQueue;

MessageQueue:单链表,根据时间优先级排列,负责获取和分发message;

Message:消息对象,被释放后放进 MessagePool , PoolSize < 50,msg.obtain后PoolSize--;

原理:

1)Handler.sendMessage()把消息放到MessageQueue;

2)MessageQueue.enqueueMessage()进行时间优先级排列;

3)Looper.loop轮询MessageQueue,通过queue.next()获得消息。

4)若 queue.next() == null ,会调用nativePollOnce方法进入阻塞状态,只有当 有消息进入 或 quit 后才会唤醒nativeWake;

5)若 queue.next() != null ,queue.dispatchMessage() 根据 message.mTarget 找到对应的Handler;

6)在Handler.handleMessage()方法中处理message;

相关面试题

1.Handler内存泄露的原因?如何解决?

原因:内部类持有了外部类的引用;

new Handler(){//创建内部类

        public void handleMessage(Message msg){

               Activity.this.click(view);//引用外部类方法,根据JVM的可达性分析,Activity正在被handler引用,所以不被释放;

        }

};

如上述事例:message持有handler,hanlder持有activity,message在没有被处理之前会一直占用内存空间;

解决方案:静态内部类+弱引用;案例如下:

private static class MineHandler extends Handler{

        private WeakReference<Activity> refernce;

        public MineHandler(Activity activity){

                this.refernce = new WeakReference<>(activity); 

        }        

}

而后在activity的onDestory()中MineHandler.removeCallbacksAndMessage()//清空管道和队列;

2.Message 和 obtainMessage 对象的创建方式、区别、如何维护消息池的?

创建方式及区别:

Message 是 new 出来的,频繁的 new 和 销毁 会造成内存抖动;

obtainMessage 是 享元模式 从MessagePool中取得;

如何维护:

static Message obtain(){

        message m = sPool;//sPool为链表,将链表的第一个元素赋值给m;

        sPool = m.next;//sPool链表指向下一个元素;

        m.next = null;

        m.flags = 0;

        sPoolSize--;//sPoolSize最大容纳50个,obtain后,size--;

        return m;

}

void recycleUnchecked(){

//Message在缓存进MessagePool前都会先置空,从而避免Message过大导致oom;

//判断当前消息池大小是否<50,是则将message插入到链表尾部,若>50直接丢弃;

        synchronized(sPoolSync) {

                if(sPoolSize < 50){

                        next = sPool;

                        sPool = this;

                        sPoolSize++;

                }

        }

}

3.Handler的post和sendMessage的区别和应用场景?postDelayed后消息队列会有什么变化?

区别:

post更新UI操作可直接在runnable内重写;

post不需要外部创建消息对象,而是根据传入的runnable封装成消息对象;

应用场景:

sendMessage:当不需要实时显示的放到队列里运行时;

postDelayed:可用于定时器;

postDelayed后消息队列的变化:postDelayed后消息队列会进行重新排序;延迟时间会与消息队列中的message的执行时间进行比较,寻找位置插入消息;

4.Handler是怎么做到一个线程对应一个Looper的,如何保证只有1个MessageQueue?

Handler在构造时,首先得到线程中保存的Looper实例,再将Looper和MessageQueue关联;

Looper.prepare()在线程中只调用1次,MessageQueue也是在prepare()中与Looper关联的;

ThreadLocal 存储了当前线程中的 Looper 对象,因为ThreadLocal 只有一个setLooper()方法,所以保证了一个线程只有一个 Looper;

5.HandlerThread原理、好处、使用场景?

原理:HandlerThread继承Thread,在自己的线程中分发和处理消息;.start()启动,.quit()释放;

好处:

1)分担 MainLooper 工作量,降低主线程压力;

2)多线程,处理任务是串行执行的,按消息发送顺序处理;

3)拥有自己的消息队列,不会干扰或阻塞UI线程;

使用场景:子线程处理耗时、多任务操作、多网络请求、多文件I/O;

6.IdleHandler调用时机及其使用场景?

Looper.myQueue().addIdleHandler(new IdleHandler(){

        public boolean queueIdle(){ //可以用来提升性能,在消息队列空闲时做事情;

                return false; //返回true,重复使用,返回false,移除

        }

});

调用时机:空闲时间;如果queue为空,最近待处理的message是延时消息,需滞后执行;

使用场景:

1)Activity启动优化:生命周期中耗时比较短,非必要代码放到idleHandler中,减少启动时间;

2)View绘制完成后,添加一个依赖于这个View的View,View.post()也可以实现;

7.消息屏障,同步屏障机制?

原理:

message的next()会判断 message.target == null ,若为空则循环找异步消息;

找到异步消息后,判断是否到处理时间,处理完成后从链表中移除;

移除屏障就是根据target和token找出屏障消息,从链表移除,并唤醒消息队列;

使用:

在Handler构造方法中传入async参数,设为true,此时handler添加的message都是异步的;

创建Message时,调用message.setAsynchronous(true);

移除屏障调用MessageQueue.removeSyncBarrier()

场景:

ViewRootImpl.scheduleTraversals()中使用了同步屏障,为了更快响应UI刷新速度;

8.Looper.quit() 和 quitSafely() 的区别?

quit():作用是把messageQueue中所有消息清空,无论是否是延迟消息;

quitSafely():只清空所有的延迟消息,并将非延迟消息派发给Handler处理;

两个方法调用后,都会调用nativeWake(),来唤醒block状态,之后才能释放线程;

9.主线程中的Looper.loop()为什么不会造成ANR?

造成ANR的原因:主线程在处理一个事件没有及时完成 或 被阻塞,导致当前事件无法执行;

结论:只要消息循环没有被阻塞,主线程就可以一直处理事件,不会ANR;

           并且当消息队列读完,没有新消息进入的时候,主线程会进入睡眠状态,因此loop并不会对CPU有过多的性能消耗;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值