Android开发Android进阶之路Android技术知识

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

2021-11-07  本文已影响0人  liys_android

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
上一篇 下一篇

猜你喜欢

热点阅读