如何防止静态字段中上下文 class 引起的内存泄漏

How do I prevent memory leak caused by context class in static fields

求助!我漏水了(至少我是这么认为的...)

下面的 instance 值是我从静态伴随对象到这个 class 的“端口”。我有一些以某种方式使用 applicationContext 的想法(我的 TODO:评论)...因为我收到此内存泄漏警告...:[=​​14=]

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

...

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

}
 

除了直接传递 AppDatabase 实例外,不要在 Repository 中传递 Context

AppDatabase 在整个应用程序中用作 Singleton 所以你可能只在应用程序 class 或其他一些 Singleton 中启动它一次,然后使用相同的 Object无处不在。

如果您使用任何依赖注入框架,如 Dagger2 或 Dagger-Hilt,create/inject 依赖将很容易。

您可以删除构造函数字段的 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 的出色回答(我已经接受),但我将post 我的结果放在这里:


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

    private val TAG = javaClass.simpleName

    val applicationContext: Context = context.applicationContext

    val appDatabase: AppDatabase = AppDatabase.getInstance(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 = applicationContext.getString(R.string.repository_all_text))
    
}

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