Handler---4部曲---4.细节补充

作者: liys_android | 来源:发表于2021-11-07 00:18 被阅读0次

    Handler---4部曲---1. 总体流程
    Handler---4部曲---2. ThreadLocal 存储主流程
    Handler---4部曲---3. MessageQueue队列
    Handler---4部曲---4.细节补充

    一. 主线程Looper.loop()死循环阻塞了,为何Activity的里代码还能执行,为什么不会ANR.

    1. 看过Activity的启动流程就知道了, Activity的生命周期全部运行在handler中, 也属于一个msg, 包括一些点击事件等, 也是msg.
    2. ANR的判断, 并不是主线程loop里判断的,而是在别的地方.

    二. Handler发送消息时,到底哪个线程的Looper处理的, 回调方法handleMessage在哪个线程?

    由Hander初始化时的Looper对象决定的.

    1. 如下:无论在任何地方初始化Handler,最终回调运行在主线程.
    new Handler(Looper.getMainLooper())
    
    1. 如下:最终回调运行在当前Handler初始化的线程.
    new Handler(Looper.myLooper())
    

    Handler的空参构造函数标记成已过时,就是为了让调用者明确,在哪个线程回调时.

    三 主线程 什么时候进行休眠? 什么时候被唤醒?

    关键标记: MessageQueue中的成员变量:;
    mBlocked ---> true主线程休眠中 , false没休眠

    通过上一篇文章我们知道, 主线程进入休眠的条件:

    //取出的消息msg ---->包括同步或异步
    msg==null  ||  没到msg执行的时间  &&  没有空闲消息   
    

    怎么唤醒:
    调用nativeWake方法即可唤醒,一共3个地方调用, 如下图:

    唤醒方法.png

    1. enqueueMessage方法,msg入队的时候

    加队列唤醒线程条件.png

    ①. 当前状态休眠 && 新消息(同步或异步)可以马上执行的时候,需要唤醒.
    ②. 当前状态休眠 && 新消息不需要马上执行 && 队列头是同步屏障消息 && 新加进来的消息异步消息


    2. removeSyncBarrier方法,删除异步消息的时候

    removeSyncBarrier.png

    3.quit方法, 放弃消息, 准备退出的时候

    image.png

    疑问:mQuitAllowed什么时候赋值的?
    ①. MessageQueue构造方法赋值

    MessageQueue构造方法.png

    ②. Looper中的构造方法赋值.


    Looper构造方法.png

    ③. 主线程和子线程 Looper 初始化的区别


    looper.prepare方法.png

    四. 子线程和主线程消息处理有什么不一样的?

    通过上面可以知道.

    1. Looper初始化的时候, 传入参数不同
    2. 主线程允许退出,子线程不允许退出
    3. next()方法返回值,子线程调用quit方法后,会唤醒当前线程,next()返回null, 会退出loop循环.
    4. 子线程无法处理mIdleHandlers空闲任务, 因为在next()里:
    if (mQuitting) {  子线程会进入这里
          return null;
    }
    
    ...后面才是处理mIdleHandlers空间任务.
    
    
    image.png

    4.子线程使用完必须释放资源(任意一个), 否则会造成内存泄漏.

            //mQueue.quit(false);
            handler().getLooper().quit();
            //mQueue.quit(true);
            handler().getLooper().quitSafely();
    

    五. 任何线程 ---> 指定子线程发送消息.

    注意: 退出 释放内存

    任何线程 ---> 指定子线程发送消息.png

    六. 如何发送 需要紧急处理的msg?

    MessageQueue.next()方法可知,队列头是同步屏障消息时,优先处理异步消息.


    image.png

    所以关键有2步:

    1. 添加同步屏障消息到队列头
    postSyncBarrier()
    
    1. 我们紧急处理的消息--->设置为异步消息

    补充:
    ①. 方法调用,可能需要反射
    ②. 同步屏障消息,用完记得删除, 上一篇文章提到过

    七. Message 里面的缓冲池.

    1. 取消息的时候, 直接从缓冲池里拿.


      image.png
    2. 释放的时候, 如果缓冲池没有满, 加到缓冲池最前面


      image.png

    相关文章

      网友评论

        本文标题:Handler---4部曲---4.细节补充

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