在 Kotlin 中有参数的单例

Singleton with argument in Kotlin

Kotlin reference 说我可以使用 object 关键字创建单例,如下所示:

object DataProviderManager {
  fun registerDataProvider(provider: DataProvider) {
    //
  }
}

但是,我想向该对象传递一个参数。例如 Android 项目中的 ApplicationContext。

有办法吗?

由于对象没有构造函数,因此我执行了以下操作以在初始设置中注入值。您可以随意调用该函数,并且可以随时调用它来修改值(或根据您的需要重建单例)。

object Singleton {
    private var myData: String = ""

    fun init(data: String)  {
        myData = data
    }

    fun singletonDemo() {
        System.out.println("Singleton Data: ${myData}")
    }
}

还有两个非常易于使用的本机 Kotlin 注入库,并且具有其他形式的单例,包括每线程、基于键等。不确定是否在您的问题上下文中,但这里有指向的链接两者:

通常在 Android 中,人们使用这样的库或 Dagger 等来完成单例参数化、范围界定等。

Kotlin 有一个名为 Operator overloading 的功能,让您可以将参数直接传递给对象。

object DataProviderManager {
  fun registerDataProvider(provider: String) {
      //
  }

  operator fun invoke(context: ApplicationContext): DataProviderManager {
      //...
      return this
  }
}

//...
val myManager: DataProviderManager = DataProviderManager(someContext)

我建议您使用这种形式在 Kotlin 的单例中传递参数,借记您的构造函数被剥夺和阻止的对象:

object Singleton {

    fun instance(context: Context): Singleton {
        return this
    }

    fun SaveData() {}
}

你在 activity

中这样称呼它
Singleton.instance(this).SaveData()

对于大多数现有答案,无需先初始化单例就可以访问 class 成员。这是一个线程安全示例,它确保在访问其任何成员之前创建单个实例。

class MySingleton private constructor(private val param: String) {

    companion object {
        @Volatile
        private var INSTANCE: MySingleton? = null

        @Synchronized
        fun getInstance(param: String): MySingleton = INSTANCE ?: MySingleton(param).also { INSTANCE = it }
    }

    fun printParam() {
        print("Param: $param")    
    }
}

用法:

MySingleton.getInstance("something").printParam()

如果您正在寻找具有多个参数的基础 SingletonHolder class。我已经创建了 SingletonHolder 泛型 class,它支持仅创建一个单例实例 class,具有一个参数、两个参数和三个参数。

link Github of the base class here

非参数(Kotlin 的默认值):

object AppRepository 

一个参数(来自上面link中的示例代码):

class AppRepository private constructor(private val db: Database) {
    companion object : SingleArgSingletonHolder<AppRepository, Database>(::AppRepository)
}
// Use
val appRepository =  AppRepository.getInstance(db)

两个参数:

class AppRepository private constructor(private val db: Database, private val apiService: ApiService) {
    companion object : PairArgsSingletonHolder<AppRepository, Database, ApiService>(::AppRepository)
}
// Use
val appRepository =  AppRepository.getInstance(db, apiService)

三个参数:

class AppRepository private constructor(
   private val db: Database,
   private val apiService: ApiService,
   private val storage : Storage
) {
   companion object : TripleArgsSingletonHolder<AppRepository, Database, ApiService, Storage>(::AppRepository)
}
// Use
val appRepository =  AppRepository.getInstance(db, apiService, storage)

超过 3 个参数:

为了实现这种情况,我建议创建一个配置对象以传递给单例构造函数。