摸鱼日记09/24 Android基础---Handler

1.Handler 的作用、要素以及流程

答:负责跨进程通信,这是因为在主线程不能做耗时操作,而子线程不能更新UI,所以当子线程中进行耗时操作后需要更新UI时,将通过Handler将有关UI的操作切换到主线程中执行。
拥有四大要素:

  1. Message(消息):需要被传递的消息,消息分为硬件产生的消息如按钮、触摸和软件生成的消息。
  2. MessageQueue(消息队列):负责消息的存储与管理,负责管理有Handler发送过来的Message。读取会自动删除消息,单链表维护,插入和删除上有优势。其next是无限循环,不断判断是否有消息,有则返回这条消息并移除。
  3. Handler(消息处理):负责Message的发送以及处理。主要向消息池发送各种消息事件,比如Handler.sendMessage()和处理相应消息事件Handler.handleMessage(),按照先进先出执行,内部使用的是单链表结构。
  4. Looper(消息池):负责关联线程以及消息的分发,在该线程喜爱从MessageQueue获取message,分发给Handler,Looper创建的时候回创建一个MessageQueue,调用loop()方法的时候消息循环开始,其中会不断调用MessageQueue的next方法,当有消息就处理,否则就阻塞在messageQueuedenext方法中。当Looper的quit()被调用时会调用messageQueue的quit,此时next会返回null,然后loop方法也就跟着退出。

具体流程如下:
在这里插入图片描述
主线程创建的时候回创建一个Looper,同时也会在Looper的内部创建一个消息队列。在创建Handler的时候取出当前线程的Looper,并通过该Looper对象获取消息队列,然后Handler在在子线程中通过MessageQueue.恩雀跃Message在消息队列中添加一条Message
通过Looper.loop()开启消息循环不断轮询调用MessageQueue.next(),取得相应的Message并且通过Handler.dispatchMessage传递给Hanler,最终调用Handler.hanlerMessage处理消息。
通过Looper.loop()开启消息循环不断轮询调用MessageQueue.next,取得相应的Message并且通过Handler.dispatchessage传递给Handler,最终调用Handler.handlerMessage处理消息。

一个线程能否创建多个Handler,Handler和Looper之间的对应关系

一个Thread只能有一个Looper,一个MessageQueue,可以有多个Handler
以一个线程为基准,他们的数量关系为:Thread(1):Looper(1):MessageQueue(1):Handler(N)。

软引用跟弱引用的区别

答: 软引用:如果一个对象只具有软引用,则内存空间充足时,垃圾回收器就不会回收它;如果内存空间不足,则会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以一直被程序使用。
弱引用:如果一个对象只具有弱引用,那么在垃圾回收线程扫描的过程中,一旦发现只具有弱引用的对象,不管当前内存空间与否,都会回收它的内存
弱引用:如果一个对象只具有弱引用,那么在垃圾回收器线程扫描的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间如何,都会回收它的内存
两者之间的根本区别在于:只具有弱引用的对象拥有更短的生命周期,可能随时被回收。而具有软引用的对象只有当内存不够时才会被回收,当内存足够时,不会被回收。

引用类型GC回收时间用途生存时间
强引用never对象的一般状态JVM停止运行时
软引用内存不足时对象缓存内存不足时终止
弱引用GC时对象缓存GC终止后
虚引用unknowunknowunknow

虚引用就是个在对象回收时发送消息的工具,对对象的生命周期来说没啥用

Handler引起内存泄漏原因以及解决方案

答:Handler允许我们发送延时消息,如果在延时期间用户关闭了Activity,那么Activity会泄露。这个泄漏是因为Message会持有Handler,而又因为Java的特性,内部类会持有外部类,使得Activity会被Handler持有,最终导致Activity持有。
解决方法:Handler定义为静态的内部类,在内部持有Activity的弱引用,并在Activity的onDestroy()中调用handler.removeCallbackAndMessage(null)及时移除所有的消息。

为什么系统不建议在子线程访问UI

答:Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态。
且为了保障UI线程的流畅,并没有选择给UI线程加上锁机制。
加上锁会导致UI的访问逻辑变得复杂
加锁机制会降低UI的访问效率,因为加锁会阻塞某些线程的执行
在这里插入图片描述
就像漏斗一样。

Looper死循环为什么不会导致应用卡死

public class NoStop {
    public static void main(String[] args) {
        while (true){
            if(false){
              //如果里面的事务超过5s还没执行完,就会报错哦!
            }
        }
    }
}

这段代码就是一段死循环,将中间的if语句视为判断message是否有next,这个程序可以一直运行不报错。对于主线程的Looper来说也是一样的
主线程的主要方法就是消息循环,一旦退出了消息循环,那么应用也就退出了,Looper.loop方法可能会引起主线程的堵塞,但是只要它的消息循环没有被阻塞,能一直处理事件就不会产生ANR异常
造成ANR的不是线程阻塞,而是主线程的Looper消息处理过程发生了任务阻塞,无法响应手势操作,不能及时刷新UI
阻塞与程序响应没有必然联系,虽然主线程在没有消息可处理的时候是阻塞的,但是只要保证有消息的时候能够立即处理,程序是不会无响应的。

使用Handler的postDealy后消息队列会有什么变化

答:如果队列中只有这个消息,那么消息不会被发送,而是计算到时唤醒时间,先将Looper阻塞,到时间唤醒它,如果此时要加入新消息,该消息队列的对头跟delay时间相比更长,则插入到头部,按照触发时间进行排序,队头的时间最小,队尾的时间最大

可以在子线程直接new一个Handler吗?

答:不可以,因为在主线程中,Activity内部包含一个Looper对象,会自动管理Looper,处理子线程中发送过来的消息,而对于子线程而言,没有任何对象维护Looper对象,所以需要我们自己手动维护。所以要在子线程中开启Handler先准备号Looper

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值