如何防止静态字段中的上下文类导致的内存泄漏

问题描述

帮助!我有漏洞(至少我是这么认为的...)

下面的 instance 值是我从静态伴随对象“移植”到这个类中的。我有一些以某种方式使用 applicationContext 的想法(我的 Todo评论)......因为我收到了这个内存泄漏警告......:

Leak message

为了避免这个问题,同时在每次调用这些函数时都不需要上下文参数(我想以某种方式将上下文存储在类中,并在它死亡时处理掉它),有什么好处练习到问题?

...

class Repository private constructor(
        var context: Context
)
{
    /**
     * Repository class,class for all communication between database and external
     * sources
     * */

    private val TAG = javaClass.simpleName

    val appDatabase: AppDatabase = AppDatabase.getInstance(context.applicationContext)

    //Todo: Test if better with applicationContext?

    companion object {
        private val TAG = this::class.java.simpleName

        @Volatile private var instance:Repository ?=null

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

        fun liveDataUserResult(staffId: StaffType=StaffType.DRIVER) =
            instance?.liveDataUserResult(staffId = staffId)

        fun liveDataDepartmentResult(staffId: StaffType=StaffType.DRIVER) =
            instance?.liveDataDepartmentResult(staffId = staffId)

...

        fun liveDatagalleryItemSiteNoInUserPath() = instance?.liveDatagalleryItemSiteNoInUserPath()

...

    }

    fun liveDatagalleryItemSiteNoInUserPath() =
        appDatabase.galleryItemDao().liveDatagalleryItemSiteNoInUserPath(allText = context.getString(R.string.repository_all_text))

}
 

解决方法

不要在 Context 中传递 Repository,除非直接传递 AppDatabase 实例。

AppDatabase 在整个应用程序中用作 Singleton 因此您可能只需在 Application 类或其他一些 Singleton 中启动它一次,并在任何地方使用相同的 Object

如果您使用任何依赖注入框架(如 Dagger2 或 Dagger-Hilt),将很容易创建/注入依赖项。

您可以删除构造函数字段的 var 以使其工作,然后它不会全局保存引用。感谢@Henry Twist。

class Repository private constructor(context: Context) {
    private val TAG = javaClass.simpleName
    var appDatabase: AppDatabase = AppDatabase.getInstance(context.applicationContext)
    companion object {
        @Volatile
        private var instance: Repository? = null
        @JvmStatic
        fun getInstance(context: Context) = instance
            ?: synchronized(this) {
                instance
                    ?: Repository(context).also { instance = it }
            }
    }
}

   
,

感谢上面 ADM 和 @Henry Twist 的出色回答(我已接受),但我会在此处发布我的结果:

grep("(?<=\\A\"x\\s=\\s')[A-Z]*",names(warnings),value = TRUE,perl = TRUE)

当然,Dagger2 或 Dagger-HILT 会更优雅。