Android: 如何创建仅一个 DatabaseRepository.kt 实例并在不同活动中使用它?

4

编辑:我需要将上下文作为参数传递给该类

(DataStorerepository是同一个类,不要混淆)

我有两个活动,AB,以及一个repository。 活动A打开活动B,并且活动B将数据保存在repository(android jetpack的一部分)中。

我在两个活动中都使用了LiveData来观察DataStore中的数据变化。

从活动B更新DataStore中的新值后,活动B中的LiveData得到了预期的新更新值。 但是,当我返回到活动A时,LiveData获取了旧数据(期望新更新数据)。

我意识到这是因为我在两个活动中创建了repository的两个实例。

如何创建只有一个repository类实例,并在两个活动中使用它? 如果有更好的方法,则欢迎提供解决方案。


你要寻找的概念叫做单例类。将仓库变成一个单例类。参考 https://dev59.com/eFQK5IYBdhLWcg3wc_jg#51835156。 - satya-p91
我没有找到在kotlin中创建单例类并且可以接收参数的合适方法。我该怎么做? - Junior
我需要向类传递参数。 - a_local_nobody
抱歉,我正在将此添加到我的问题中。 - Junior
5个回答

4

基于静态引用和将Context作为类参数传递的单例模式会导致内存泄漏。另一方面,您可以使用Application类来创建所需类的一个实例。

class YourApp : Application(){
    val repository by lazy { YourRepository(this) }
}

你可以使用以下代码在其他地方访问它:(context.applicationContext as YourApp).repository。同时,别忘了在清单文件中声明应用程序的名称android:name=...


3

传统的单例模式(如@DanBaruch所提到的)可以工作,但是 Kotlin 有一个很棒的关键字叫做object,通过它,你可以在整个应用程序中创建单例实例。

object DatabaseRepository{
    private lateinit var context: Context

    fun setAppContext(context: Context){
        this.context = context
    }
}

为了从 Application 类中设置 context,请按以下步骤进行:
DatabaseRepository.setAppContext(this)

我需要向类传递参数。 - Junior
你想传递什么,你仍然可以直接将变量放在对象中,因为它是单例。 - Rajan Kali
我需要传递一个上下文。 - Junior
理想情况下,您可以在DatabaseRepository内部创建一个上下文变量,并使用DatabaseRepository.context = context进行设置,但这不仅在此情况下,而且对于任何单例模式都不是推荐的方法,因为单例变量具有应用程序的生命周期,这意味着它将保持上下文活动状态,这是不好的,并且在存储库中使用上下文将使存储库与Android Framework耦合,从而难以进行单元测试。 - Rajan Kali
我会先测试一下,如果它能正常工作,那么我会接受它。谢谢 :) - Junior
显示剩余3条评论

2
在Kotlin中,有两种方法可以创建单例模式。
  1. 使用object关键字 - 这样,我们可以在构造函数中添加任何参数。

  2. 或者我们可以创建一个单例类,就像这样:


class DbRepository () {

    companion object {
        private var instance: DbRepository? = null

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

}



0

你能使用单例设计模式吗? 如果可以:

class DataSource private constructor(private var mP1: Any?, private var mP2: Any?) {

fun setParam1(p1: Any) {
    mP1 = p1
}

fun setParam2(p2: Any) {
    mP2 = p2
}

companion object {
    private var mInstance: DataSource? = null
    fun getInstance(p1: Any, p2: Any): DataSource {
        if (mInstance == null)
            mInstance = DataSource(p1, p2)
        return mInstance
    }
}
}

我在Android Studio中编写了这个模型,并将其转换为Kotlin,但我不知道它是否是有效的Kotlin代码。

有两个选项,要么在第一次调用getInstance时向其发送参数,然后以nulls的形式再次调用它,如下所示:

//First time calling:
DataSource mMyInstance = DataSource.getInstance(param1, param2);
 //Second time calling:
 DataSource mMyInstance2 = DataSource.getInstance(null,null);

或者使用设置函数,保持getInstance不带参数。请注意,选择选项1会使你使用无用的参数调用getInstance,但会确保你不会忘记设置任何需要的参数,而选择选项2可能会有更简洁的“getInstance”调用,但会强制你始终设置参数,我认为这是两个选项中更糟糕的选项。


1
我需要向类传递参数,而我正在使用 Kotlin。 - Junior
我不知道 Kotlin,也不知道如何将其转换为 Kotlin,但从我所了解的来看,似乎相当容易。无论如何,我会更新代码以提供参数选项,您可以使用最适合您需求的选项。关于转换它,我认为 Android Studio 中有一个工具可以实现。 - Dan Baruch

0

由于对象关键字不允许参数,我建议使用依赖注入(如Dagger/Hilt)创建单例并将其注入到您的视图模型中。

阅读官方文档以了解入门知识是值得的。

如果您还没有使用依赖注入框架的经验,您应该先了解这个主题,然后再决定是否要将DI集成到您的应用程序代码中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接