Using room as singleton in kotlin

后端 未结 5 1240
被撕碎了的回忆
被撕碎了的回忆 2021-02-01 08:24

I\'m trying to use Room as singleton so I didn\'t have to invoke Room.databaseBuilder() -which is expensive- more than once.

@Database(entities = ar         


        
5条回答
  •  孤街浪徒
    2021-02-01 09:09

    I found a solution so here is the answer for future me and any one who might have the same problem.


    After some research, I found that I have two options.

    1. use Double-checked locking
    2. use Initialization-on-demand holder idiom

    so I considered implementing one of them, but this doesn't feel right in kotlin too much boilerplate code :p


    so after more research, I stumbled upon this great article which provides an excellent solution which uses Double-checked locking but in an eligant way.

    my code becomes like this:

    companion object : SingletonHolder({
           Room.databaseBuilder(it.applicationContext, AppDatabase::class.java, "train.db").build()
    })
    

    from the article:

    A reusable Kotlin implementation:

    We can encapsulate the logic to lazily create and initialize a singleton with argument inside a SingletonHolder class. In order to make that logic thread-safe, we need to implement a synchronized algorithm and the most efficient one — which is also the hardest to get right — is the double-checked locking algorithm.

    open class SingletonHolder(creator: (A) -> T) {
        private var creator: ((A) -> T)? = creator
        @Volatile private var instance: T? = null
    
        fun getInstance(arg: A): T {
            val i = instance
            if (i != null) {
                return i
            }
    
            return synchronized(this) {
                val i2 = instance
                if (i2 != null) {
                    i2
                } else {
                    val created = creator!!(arg)
                    instance = created
                    creator = null
                    created
                }
            }
        }
    }
    

    Extra: if you want Singleton with two arguments

    open class SingletonHolder2(creator: (A, B) -> T) {
        private var creator: ((A, B) -> T)? = creator
        @Volatile private var instance: T? = null
    
        fun getInstance(arg0: A, arg1: B): T {
            val i = instance
            if (i != null) return i
    
            return synchronized(this) {
                val i2 = instance
                if (i2 != null) {
                    i2
                } else {
                    val created = creator!!(arg0, arg1)
                    instance = created
                    creator = null
                    created
                }
            }
        }
    }
    

提交回复
热议问题