单例使用会在 kotlin 中造成内存泄漏

Singleton usage creates memory leak in kotlin

尝试在另一个单例中使用单例 class,但不知何故它让我出现内存泄漏。

我该如何改进它?

这是我的示例单例实现

class FirstSingletonClass(val context: Context) {
    companion object {
        @Volatile
        private var instance: FirstSingletonClass? = null

        fun getInstance(context: Context): FirstSingletonClass =
                instance ?: synchronized(this) {
                    instance ?: FirstSingletonClass(context).also { instance = it }
                }

    }

   private val sSingletonClass: SecondSingletonClass = Injection.provideSecondSingletonClass(context)
}

SecondSingletonClass块

class SecondSingletonClass(val context: Context) {
    companion object {
        @Volatile
        private var instance: SecondSingletonClass? = null

        fun getInstance(context: Context): SecondSingletonClass =
                instance ?: synchronized(this) {
                    instance ?: SecondSingletonClass(context).also { instance = it }
                }

    }

   private val fSingletonClass: FirstSingletonClass = Injection.provideFirstSingletonClass(context)
}

注入class

object Injection {
    fun provideSecondSingletonClass(context: Context): SecondSingletonClass = SecondSingletonClass.getInstance(context)
    fun provideFirstSingletonClass(context: Context): FirstSingletonClass = FirstSingletonClass.getInstance(context)
}

因此,当我初始化 属性 - private val sSingletonClassprivate val fSingletonClass 时,它会产生内存泄漏。但是如果我在函数块的某处调用我的单例 class 它工作正常。

是否可以实现我想要的?或者我应该明确地使用它...

你在这里泄露了上下文。您不应该持有对 Context 的长期引用。您可以将上下文作为需要它们的 FirstSingletonClass 和 SecondSingletonClass 方法中的参数。

Android 工作室应该给你这个警告:

不要将 Android 上下文 类 放在静态字段中(对 SecondSingletonClass 的静态引用,其中的字段上下文指向 Context);这是一个内存泄漏(并且还会破坏 Instant 运行)

您的代码可以简化为:

object FirstSingletonClass {
    private val sSingletonClass = SecondSingletonClass
}

object SecondSingletonClass {
    private val fSingletonClass = FirstSingletonClass
}

问题:您正在将上下文实例传递给单例,上下文可能是 activity、服务等。它可能会导致上下文泄漏.

解决方法:改用applicationContext

class FirstSingletonClass(val context: Context) {
    companion object {
        @Volatile
        private var instance: FirstSingletonClass? = null

        fun getInstance(context: Context): FirstSingletonClass =
            instance ?: synchronized(this) {
                instance ?: FirstSingletonClass(context.applicationContext).also { instance = it }
            }
    }

    private val sSingletonClass: SecondSingletonClass = Injection.provideSecondSingletonClass(context)
}

class SecondSingletonClass(val context: Context) {
    companion object {
        @Volatile
        private var instance: SecondSingletonClass? = null

        fun getInstance(context: Context): SecondSingletonClass =
            instance ?: synchronized(this) {
                instance ?: SecondSingletonClass(context.applicationContext).also { instance = it }
            }

    }

    private val fSingletonClass: FirstSingletonClass = Injection.provideFirstSingletonClass(context)
}