Singleton with parameter in Kotlin

后端 未结 11 1105
无人及你
无人及你 2020-11-30 21:51

I am trying to convert an Android app from Java to Kotlin. There are a few singletons in the app. I used a companion object for the singletons without constructor parameters

相关标签:
11条回答
  • 2020-11-30 22:24

    Here's a neat alternative from Google's architecture components sample code, which uses the also function:

    class UsersDatabase : RoomDatabase() {
    
        companion object {
    
            @Volatile private var INSTANCE: UsersDatabase? = null
    
            fun getInstance(context: Context): UsersDatabase =
                INSTANCE ?: synchronized(this) {
                    INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
                }
    
            private fun buildDatabase(context: Context) =
                Room.databaseBuilder(context.applicationContext,
                        UsersDatabase::class.java, "Sample.db")
                        .build()
        }
    }
    
    0 讨论(0)
  • 2020-11-30 22:27

    Thread-Safe Solution # Write Once; Use Many;

    It's a good solution to create a class implementing the logic of singleton which also holds the singleton instance, like the following.

    It instantiates the instance using Double-Check Locking in a synchronized block to eliminate possibility of race condition in multi-threaded environments.

    SingletonHolder.kt

    open class SingletonHolder<out T, in A>(private val constructor: (A) -> T) {
    
        @Volatile
        private var instance: T? = null
    
        fun getInstance(arg: A): T {
            return when {
                instance != null -> instance!!
                else -> synchronized(this) {
                    if (instance == null) instance = constructor(arg)
                    instance!!
                }
            }
        }
    }
    

    Usage

    Now in each class that you want to be singleton, write a companion object extending the above class. SingletonHolder is a generic class that accepts type of target class and its requiring parameter as generic params. It also needs a reference to the constructor of target class which is used for instantiating an instance:

    class MyManager private constructor(context: Context) {
    
        fun doSomething() {
            ...
        }
    
        companion object : SingletonHolder<MyManager, Context>(::MyManager)
    }
    

    Finally:

    MyManager.getInstance(context).doSomething()
    
    0 讨论(0)
  • 2020-11-30 22:29

    If the only parameter you need is the application Context, then you can initialize it to a top level val, early in a ContentProvider, like the Firebase SDK does.

    Since declaring a ContentProvider is a bit cumbersome, I made a library that provides a top level property named appCtx for all places where you don't need an Activity or other special lifecycle bound context.

    0 讨论(0)
  • 2020-11-30 22:31

    The method synchronized() is marked as deprecated in the common standard library so an alternative would be this:

    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 }
        }
    }
    
    0 讨论(0)
  • 2020-11-30 22:35
    Singletons
    

    Singletons are used often enough for a simpler way of creating them to exist. Instead of the usual static instance, getInstance() method and a private constructor, Kotlin uses the object notation. For consistency, object notation is also used to define static methods.

     object CommonApiConfig {
    private var commonApiConfig: CommonApiConfig? = null
    fun getInstance(): CommonApiConfig {
        if (null == commonApiConfig) {
            commonApiConfig = CommonApiConfig
           }
        return CommonApiConfig.commonApiConfig!!
       }
    }
    
    0 讨论(0)
提交回复
热议问题