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

时间:2018-11-28 02:29:46

标签: android kotlin memory-leaks android-handler

我的自定义处理程序类中发生了某些内存泄漏,但不确定如何解决。在线签出了一些示例,但是我的代码没有什么特别的,因此不确定如何进行操作:

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 Studio不断提示“此处理程序类应该是静态的,否则可能会发生泄漏”。有什么主意吗?

2 个答案:

答案 0 :(得分:2)

Android Studio抱怨很合理。问题在于匿名类会捕获对创建它们的父类的引用。

基本上有两种解决方法:“不美观”和“丑陋”。它们都与WeakReference有关。

#1 不太好的解决方案是创建一个需要较弱引用的类

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)
    }
}

活动中:

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将立即被调用,并且将仅捕获对象内部的弱引用,并且还将返回直到object为止的最后一个表达式。

#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....
    }

}

答案 1 :(得分:0)

匿名类(如您的类)不是静态的。您可以将匿名类替换为普通类(只需创建扩展RetryCallback的类),然后将所有需要的对象作为构造函数参数传递。