第一天(Handler)

问题1:在子线程中一定不能进行UI更新?

答:不一定,因为当我们在setText方法时,会走一个

checkForRelayout()方法,
而在这个方法里面最后都会走 requestLayout();invalidate();这二个方法而在requestLayout()方法里面走一个
ViewRootImpl.requestLayout()方法, 在这里会对线程进行检测,checkThread();,mThread肯定是是主线程,如果在子线程中则Thread.currentThread()肯定不等于main所以抛异常
 if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }

如果invalidate();这个方法优化于checkThread()则不会异常

问题2:Handler为什么会内存泄漏,解决的方法

答:因为当Handler发送一个消息出去的时候,已经将消息存入了消息队列MessageQueue里面,而在Looper的looper方法会无限循环的向消息队列里取消息,当一个Activity销毁时,发送出去的消息并没有销毁.而Handler是一个内部类,内部类会执有外部类引用,也就是Activity.最后都会执行Handler.handlerMeaager方法.

解决方法:1:弱引用Activity;

                2:onDestory里将handler设置为null;

问题3:handler.post方法为什么是执行在主线程

答:当handler.post一个Runnable方法时,会将Runnable封装在Message里的一个callback里,最后放入MeaageQueue里面,而Looper.looper取消息的时候是在主线程,取到消息最后走的是Handler.dispatchMessage方法,里面会判断message.callback是否为空,不为空则会走Runnable的run方法

问题4:在子线程中能直接创建Handler对象?

答:不能,因为为子线程中直接创建Handler对象时会执行

Looper.myLooper();方法获取Looper,如果Looper为空时就会抛异常.

解决方法: 在创建handler的时候先执行

Looper.prepare();

源码分析

Handler主要是用来在子线程到主线程之间进行切换.

当我们启动APP的时候,最开始走的是ActivityThread类里的main方法,在这里面开始会执行Looper.prepareMainlooper方法,里会会实例化一个主线程Looper对像,并保存在ThreadLocal成员变量里,而在new Looper的时候,则又会在构造方法里实例化一个MessageQueue方法里,所以在进入APP的时候,就会实例经主线程的Looper和MessageQueue而且一定是唯一的.最后然后走Looper.loop方法进行轮询取消息.

当我们创建Handler的时候,会将主线程里的Looper 和MessgeQueue赋值给其成员变量,当sendMessage的时候,不管是发送什么样的消息,最终都走的是enqueueMeaage方法就是准备将消息压入MessageQueue里面去,当然在这之中会将handler传给Message,所以message会执有Handler引用.

最后在Looper.loop轮询到方法的时候,就会拿到message的target也就是Handler,会调用到其dispatchMessage方法中对消息进行分发,因为loop()这个方法是在主线程的,所以dispatchMessage分发的消息也是在主线程的执行的,最最后就走到了我们的handlerMessage方法里面,就可以在主线程的进行UI更新.

面试题第二天

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值