• Handle


    1.Handler的实现原理

    从四个方面看 Handler Message MessageQueue Looper
    Handler: 负责消息的发送和处理
    Message: 消息对象,类似于链表的一个结点 ;
    MessageQueue: 消息队列,用于存放消息对象的数据结构 ;
    Looper: 消息队列的处理者(用于轮询消息队列的消息对象 )
    Handler 发送消息时调用 MessageQueue enqueueMessage 插入一条信息到 MessageQueue,Looper 不断轮询调用
    MeaasgaQueue next 方法 如果发现 message 就调用 handler dispatchMessage dispatchMessage 被成功调 用,接着调用handlerMessage()

    2.子线程中能不能直接new一个Handler,为什么主线程可以 主线程的Looper第一次调用loop方法,什么时候,哪个类

            不能,因为Handler 的构造方法中,会通过 Looper.myLooper() 获取 looper 对象,如果为空,则抛出异常, 主线程则因为已在入口处ActivityThread main 方法中通过 Looper.prepareMainLooper() 获取到这个对象, 并通过 Looper.loop() 开启循环,在子线程中若要使用 handler ,可先通过 Loop.prepare 获取到 looper 对象,并使用 Looper.loop()开启循环。

    3.Handler导致的内存泄露原因及其解决方案

    1.Java 中非静态内部类和匿名内部类都会隐式持有当前类的外部引用
    2. 我们在 Activity 中使用非静态内部类初始化了一个 Handler, Handler 就会持有当前 Activity 的引用。
    3. 我们想要一个对象被回收,那么前提它不被任何其它对象持有引用,所以当我们 Activity 页面关闭之后 , 存在引用关 系:" 未被处理 / 正处理的消息 -> Handler 实例 -> 外部类 ", 如果在 Handler 消息队列 还有未处理的消息 / 正在处理消 息时 导致Activity 不会被回收,从而造成内存泄漏
    解决方案 :
    1. Handler 的子类设置成 静态内部类 , 使用 WeakReference弱引用持有 Activity 实例
    2. 当外部类结束生命周期时,清空 Handler 内消息队列

    4.一个线程可以有几个Handler,几个Looper,几个MessageQueue对象

            一个线程可以有多个Handler, 只有一个 Looper 对象 , 只有一个 MessageQueue 对象。 Looper.prepare() 函数中知道,。在Looper prepare 方法中创建了 Looper 对象,并放入到 ThreadLocal 中,并通过 ThreadLocal 来获取 looper 的对象, ThreadLocal 的内部维护了一个 ThreadLocalMap ,ThreadLocalMap 是以当前 thread 做为 key , 因此可以得 知,一个线程最多只能有一个Looper 对象, 在 Looper 的构造方法中创建了 MessageQueue 对象,并赋值给 mQueue
    字段。因为 Looper 对象只有一个,那么 Messagequeue 对象肯定只有一个。

    5.Message对象创建的方式有哪些 & 区别,Message.obtain()怎么维护消息池的

    1.Message msg = new Message();
    每次需要 Message 对象的时候都创建一个新的对象,每次都要去堆内存开辟对象存储空间
    2.Message msg = Message.obtain();
    obtainMessage 能避免重复 Message 创建对象。它先判断消息池是不是为空,如果非空的话就从消息池表头的 Message取走 , 再把表头指向 next
    如果消息池为空的话说明还没有 Message 被放进去,那么就 new 出来一个 Message 对象。消息池使用 Message 链表 结构实现,消息池默认最大值 50 。消息在 loop 中被 handler 分发消费之后会执行回收的操作,将该消息内部数据清空
    并添加到消息链表的表头。
    3.Message msg = handler.obtainMessage(); 其内部也是调用的 obtain() 方法

    6.Handler 有哪些发送消息的方法

    sendMessage(Message msg)
    sendMessageDelayed(Message msg, long uptimeMillis)
    post(Runnable r)
    postDelayed(Runnable r, long uptimeMillis)
    sendMessageAtTime(Message msg,long when)

    7.HandlerpostsendMessage的区别和应用场景

    1. 源码
    sendMessage
    sendMessage-sendMessageAtTime-enqueueMessage
    post
    sendMessage-getPostMessage-sendMessageAtTime-enqueueMessage getPostMessage 会先生成一个 Messgae,并且把 runnable 赋值给 message callback
    2.Looper->dispatchMessage 处理时
    1. public void dispatchMessage(@NonNull Message msg) {
    2. if (msg.callback != null) {
    3. handleCallback(msg);
    4. } else {
    5. if (mCallback != null) {
    6. if (mCallback.handleMessage(msg)) {
    7. return;
    8. }
    9. }
    10. handleMessage(msg);
    11. }
    12. }
    dispatchMessage 方法中直接执行 post 中的 runnable 方法。
    sendMessage 中如果 mCallback 不为 null 就会调用 mCallback.handleMessage(msg) 方法,如果 handler 内的 callback不为空,执行 mCallback.handleMessage(msg) 这个处理消息并判断返回是否为 true ,如果返回 true ,消息 处理结束,如果返回false,handleMessage(msg) 处理。否则会直接调用 handleMessage 方法。
    post方法和 handleMessage 方法的不同在于,区别就是调用 post 方法的消息是在 post 传递的 Runnable 对象的 run 方法中处理,而调用sendMessage 方法需要重写 handleMessage 方法或者给 handler 设置 callback ,在 callback
    handleMessage 中处理并返回 true
    应用场景
    post 一般用于单个场景 比如单一的倒计时弹框功能 sendMessage 的回调需要去实现 handleMessage Message 则做为参数 用于多判断条件的场景。

    8.handler postDealy后消息队列有什么变化,假设先 postDelay 10s, postDelay 1s, 怎么处理这2条消息sendMessageDelayed-sendMessageAtTime-sendMessage

  • 相关阅读:
    景联文科技提供高质量人像采集服务,助力3D虚拟人提升逼真度
    扑克牌问题
    linux集群上的SCHRODINGER 分子对接工作流程
    Shiro
    在服务器上部署 Nginx 并设置图片服务器
    应用安全迁移的五个步骤
    如何在 Python 中运行无头浏览器?
    【小航的算法日记】贪心算法
    报价33万的极星电动车,一组电池就高达40万?
    C#的Switch语句2(case后的值与模式匹配)
  • 原文地址:https://blog.csdn.net/qq_14931305/article/details/126245284