如何避免由于自定义静态处理程序 class 而导致的内存泄漏?

How to avoid memory leaks due to custom static handler class?

我的自定义处理程序 class 中发生了某些内存泄漏,但不确定如何修复它。在网上查了几个例子,但没有什么是我的代码特有的,所以不确定如何去做:

private val startupCallback = object: RetryCallback(NUMBER, DELAY) {
        override fun onRetry(retryCount: Int) {

            mySdkApi.applicationStartup(this)
        }

        override fun onCompleted(): Boolean {
            updateStatus(Callback.Status.StartUpSDK)

            return true
        }

        override fun onFailed(e: MyException?) {
            updateStatus(Callback.Status.StartUpSDK, "", e)
        }
    }

Android 工作室不断提示 "This handler class should be static or leaks might occur"。有什么想法可以解决吗?

匿名 classes(像你的)是非静态的。您可以将匿名 class 替换为普通 class(只需创建 class 扩展 RetryCallback)并将所有需要的对象作为构造函数参数传递。

Android 工作室的抱怨是有道理的。问题是匿名 classes 捕获对创建它们的父 class 的引用。

基本上有两个解决方案 "not pretty" 和丑陋的。)它们都是关于 WeakReference 的。

#1 不太好的解决方案是制作一个 class 将采用弱引用

class ApiRetryCallback(activity: Activity): RetryCallback(NUMBER, DELAY) {

    private val weakActivity = WeakReference(activity)

    override fun onRetry(retryCount: Int) {

        weakActivity.get()!!.mySdkApi.applicationStartup(this) //or weakThis.get()? to swallow null cases
    }

    override fun onCompleted(): Boolean {
        weakActivity.get()!!.updateStatus(Callback.Status.StartUpSDK)

        return true
    }

    override fun onFailed(e: MyException?) {
        weakActivity.get()!!.updateStatus(Callback.Status.StartUpSDK, "", e)
    }
}

在activity中:

private val startupCallback = ApiRetryCallback(this) //this is MainActivity here

#2 丑陋的解决方案基于一个事实,即 lambda 应该捕获父引用,只有在直接使用它的地方。所以我想到了这个替换,但我没有在调试器中看到强引用,但你应该检查一下:

private val startupCallback = {
    val weakActivity = WeakReference(this@MainActivity)

    object : RetryCallback(NUMBER, DELAY) { //returned as last expression

        override fun onRetry(retryCount: Int) {

            weakActivity.get()!!.mySdkApi.applicationStartup(this) //or weakThis.get()? to swallow null cases
        }

        //....else methods....
    }

}()

此处将立即调用 lambda 并仅捕获对象内部的弱引用,它还会 return 最后一个表达式即对象。

#3 写的时候想到了第三个方案,接近#2

private val startupCallback = WeakReference(this).let { //this here is MainActivity
    val weakActivity = it //it of let scope wich is WeakReference

    object : RetryCallback(NUMBER, DELAY) { //returned as last expression

        override fun onRetry(retryCount: Int) {

            weakActivity.get()!!.mySdkApi.applicationStartup(this) //or weakThis.get()? to swallow null cases
        }

        //....else methods....
    }

}