美文网首页Android Framework开发
Android 体系架构 Handler分析

Android 体系架构 Handler分析

作者: 为自己代颜_ | 来源:发表于2023-04-05 11:12 被阅读0次
    image.png

    Handler在Android 一个app内部使用 不会跨进程使用,解决线程之间的问题

    面试相关问题:


    image.png

    1.一个线程几个handler?
    handler是个类 在一个线程中可以有n多个。比如可以为主线程创建多个,但是一个线程只有一个looper


    image.png

    所有与主线程通信的底层逻辑都是使用的handler通信
    使用过程中可能会导致内存泄漏

    2.线程间通信的具体原理(内存共享)
    工作流程


    image.png image.png image.png image.png

    message作为一个内存块,从子线程到主线程,再取出来用

    1. 内存泄漏
      3.1内部类为什么会持有外部类的引用(最简单的一知半解的解释)
      延伸知识点:


      image.png

    通过引用链分析是否存在GCRoots,如果存在可能存在内存泄漏的风险

    面试:内部类为什么会持有外部类的引用
    这是因为内部类虽然和外部类写在同一个文件中,但是编译后还是会生成不同的class文件,其中内部类的构造函数中会传入外部类的实例,然后就可以通过this$0访问外部类的成员。

    其实也挺好理解的吧,因为在内部类中可以调用外部类的方法,变量等等,所以肯定会持有外部类的引用的。
    相关链接:https://blog.csdn.net/cpcpcp123/article/details/122000663

    3.2handler中 在activity中new了一个handler 则handler持有了外部activity的对象,那谁持有了handler对象呢?
    Framwork模块学习handler讲解部分5
    这是问题关键源码分析如下:


    image.png

    其中this 就是 handler对象,handler被message持有了,而message被handler发送的时候被加入到了MessageQueue中又被MessageQueue持有了 ,而MessageQueue是handler初始化的时候被looper持有的 如下图源码


    image.png image.png image.png

    MessageQueue又是final类型 一旦创建是不可改的
    而looper初始化是Looper.prepareMainLooper 跟踪源码如下:


    image.png image.png static声明的变量一定会被GCROOTS引用,生命周期跟App是一致的.形成了如下引用链 image.png
    关键问题分析,正常发送的message如果被Activity即使处理了就不会导致内存泄漏;但是如果发送的是延迟20s才收到,activity在没有收到之前就已经finish掉了,这种情况就导致GCROOTS持有链一直都在持有就无法释放;解决办法1如下: image.png

    声明为static的内部类,因为static的内部类不会持有外部当前Activity的引用对象,但是handle对象怎么才调用activity的方法呢?那就再弱或软引用当前的activity进行引用;
    还有其它的方法比如activity销毁的时候直接remove掉MessageQueue中的消息这样的话也会阻断这个持有链 这样GCROOTS就不会引用它了 就会被回收了。

    4.为何主线程可以new handler,子线程中该如何使用主要是要明白原理 image.png

    主线程new handler的时候 在handler的构造方法会去调用取到Looper.myLooper对象,而这个Looper对象是在app启动的时候在ActivityThread中已经在当前主线程创建好了,所以可以取到。所以在子线程创建handler的时候 子线程中没有looper对象要提前prepare好

    5. image.png

    wait()会等notifyAll来唤起

    6.epoll机制 linux内核中的一种可拓展文件IO事件处理机制,一种管理阻塞的机制底层是Linux,只有研究Linux系统的才会研究epoll , linux 2.3之后 出现epoll机制 研究C和C++的也都不去研究源码,java的Ngix就是基于epoll的机制

    epoll之前会遍历所有的io流列表 不管是不是与本流相关 如下: 复杂度O(n)


    image.png

    epoll之后 只遍历相关的io流 提升了性能复杂度O(1) epoll_wait会把相关的流赋值给steam,


    image.png

    epoll创建是在MessageQueue创建的时候Init初始化的,初始化的时候便把事件注册函数注册了


    image.png

    wait的过程中是如何唤醒的呢 往消息队列放消息的时候 此处唤醒的是一个epoll所对应的事件,此过程是在Linux内部看不懂你的另一个字节码处理的


    image.png

    7 同步屏障
    如下图正常消息队列是挨个同步遍历的,但是如果保证这个消息还没遍历到就刷新呢,就用到了消息屏障


    image.png

    屏障消息target为null;


    image.png

    消息分类三种类型:
    上图中白色的为正常的消息;红色的是屏障消息;黄色的是异步部消息
    设置消息屏障目的就是级别高的先执行
    整个设计流程:
    也就是,只要有一个屏障消息为第一个消息 ,那么相当于再这个时间添加了屏障(这里不会主动唤醒线程) ,那么后面只要后面入队的消息为异步消息 都优先执行,没有则一直阻塞,如果这个时候一个普通消息sendMessageDelayed(getPostMessage®, 0)入队 会触发唤醒线程,有异步消息 则取出此异步消息返回 然后继续阻塞线程 , 直到移除屏障消息(这里才会触发唤醒线程)。没有异步消息 则取出这个普通消息 返回。

    关于消息屏障的触发时机 详细解析:
    https://blog.csdn.net/z936689039/article/details/128989367

    8 image.png 9 image.png 10 image.png

    11 Looper死循环为啥不会ANR 解析如下 不是一个概念


    image.png

    相关文章

      网友评论

        本文标题:Android 体系架构 Handler分析

        本文链接:https://www.haomeiwen.com/subject/hfbsddtx.html