• Kotlin中正确的使用Handler


    Handler造成的内存泄漏

    Handler中的几个关键角色:

    • Handler:负责发送和处理Message消息;
    • Message:消息载体;
    • MessageQueue:消息队列,负责存储Message消息。
    • Looper:每个Thread中只有一个对应的Looper,负责不断循环从MessageQueue中获取Message,并且不断通过msg.target(Handler)将消息取出来并执行。

    Handler的详解参见:Android异步消息处理机制之Handler

    如果HandlerActivity中是以非静态内部类的方式初始化的,那么Handler默认就会持有Activity的实例,因为在Java中:非静态内部类默认会持有外部类的实例,而静态内部类不会持有外部类的实例

    Handler中发送延迟消息,如使用sendMessageDelayed(msg, delayMillis)发送消息,并且在msg消息还在MessageQueue中没有得到处理时就关闭了当前页面(Activity调用了finish()),类持有关系是Looper -> MessageQueue -> Message -> Handler -> Activity,而在UI线程中的Looper.loop()是会一直执行的,即UI线程中Looper的生命周期跟Application一样长,从而导致Activity不能及时被回收导致内存泄漏。

    通过static内部类 + WeakReference弱引用的方式可以避免内存泄漏的产生。

    Kotlin中使用Handler

    Kotlin中,并不能直接通过static关键字来声明静态类,那么如何声明一个静态内部类呢?其实在Kotlin中,直接在一个类中声明另一个类,经过Kotlin编译器之后自动就是static静态内部类了,如:

    //Outer.kt
    class Outer {
        private val bar: Int = 1
    
        class Inner {
            //val value = bar //错误!静态内部类不能访问外部类的成员变量,所以这里访问不了外部类的bar
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    反编译成Java文件之后

    public final class Outer {
       private final int bar = 1;
    
       public static final class Inner {
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    可以看到编译之后Inner内部类已经是静态内部类了。如果想访问外部类的成员变量,可以将内部类声明为非静态内部类,只需要加上inner关键字就可以了,如下:

    //Outer.kt
    class Outer {
        private val bar: Int = 1
    
        inner class Inner {
            val value = bar //非静态内部类能够直接访问外部类的成员变量
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    反编译成Java文件之后:

    public final class Outer {
       private final int bar = 1;
    
       public final class Inner {
          private final int value;
    
          public final int getValue() {
             return this.value;
          }
    
          public Inner() {
             this.value = Outer.this.bar;
          }
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    通过inner关键字转换成非静态内部类,可以直接访问外部类的成员变量了。我们知道了如何在Kotlin里写静态内部类,那么就可以在Kotlin里以static内部类 + WeakReference弱引用的方式来使用Handler了。

    class HandlerActivity : AppCompatActivity() {
        companion object {
            const val WHAT_HINT_TEXT = 1000 //MSG_WHAT
        }
    
        private val mOutPut = "我输出了" //成员变量
        private val weakHandler by lazy { WeakReferenceHandler(this) }
    
        //static + 弱引用
        class WeakReferenceHandler(obj: HandlerActivity) : Handler(Looper.getMainLooper()) {
            private val mRef: WeakReference = WeakReference(obj)
    
    
            override fun handleMessage(msg: Message) {
                mRef.get()?.run {
                    when (msg.what) {
                        WHAT_HINT_TEXT -> println(mOutPut) //可以直接访问Activity中的变量
                    }
                }
            }
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            weakHandler.sendEmptyMessageDelayed(WHAT_HINT_TEXT, 5000)
        }
    
        override fun onDestroy() {
            //退出页面时,置空所以的Message
            weakHandler.removeCallbacksAndMessages(null)
            super.onDestroy()
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    上述代码即是在KotlinUI线程中使用Handler的一个例子,通过static + 弱引用 + onDestroy中remove Messages避免内存泄漏。

  • 相关阅读:
    【面向对象依赖关系概念总结】面向对象程序设计的五种依赖关系
    PyTorch学习笔记(一)
    IDEA自定义注释模版
    Jmeter分布式压力测试
    FPGA纯vhdl实现XGMII接口10G万兆网UDP协议DMA传输 配合10G Ethernet PCS/PMA使用 提供工程源码和技术支持
    微擎模块 最新抽奖助手 5.2.3 小程序前台+后台,机器人增加时的逻辑优化·后台设置是否允许红包抽奖
    加密与安全_深入了解Hmac算法(消息认证码)
    java版工程管理系统Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码
    Spring Boot深度解析:快速开发的秘密
    重磅!元宇宙招聘会来袭,60多所高校学生参加...
  • 原文地址:https://blog.csdn.net/u013700502/article/details/126193116