【问题标题】:How can I make this singleton simpler in Kotlin?如何在 Kotlin 中使这个单例更简单?
【发布时间】:2018-07-30 18:59:19
【问题描述】:

如何在 Kotlin 中简化这个单例以进行 Android 房间数据库初始化?

@Database(entities = arrayOf(Book::class, User::class), version = 1)
abstract class AppDatabase : RoomDatabase() {

    abstract fun bookModel() : BookDao
    abstract fun userModel() : UserDao

    companion object {
        private var INSTANCE: AppDatabase? = null

        fun getInMemoryDatabase(context: Context): AppDatabase {
            if (INSTANCE == null) {
                INSTANCE = Room.inMemoryDatabaseBuilder(context.applicationContext, AppDatabase::class.java).build()
            }
            return INSTANCE!!
        }

        fun destroyInstance() {
            INSTANCE = null
        }
    }
}

【问题讨论】:

    标签: android kotlin android-room


    【解决方案1】:

    您可以使用数组文字 ([]) 代替 arrayOf,并且可以使用 elvis 运算符进行空值检查。见here

    @Database(entities = [Book::class, User::class], version = 1)
    abstract class AppDatabase : RoomDatabase() {
    
        abstract fun bookModel() : BookDao
        abstract fun userModel() : UserDao
    
        companion object {
            private var INSTANCE: AppDatabase? = null
    
            fun getInMemoryDatabase(context: Context): AppDatabase { 
                INSTANCE = INSTANCE ?: Room.inMemoryDatabaseBuilder(context.applicationContext, AppDatabase::class.java).build()
                return INSTANCE!!
            }
        
            fun destroyInstance() {
                INSTANCE = null
            }
        }
    }
    

    由于您需要实例,因此您必须将其保存在某个地方,因此使用 companion object 对我来说似乎是一个合理的解决方案。

    如果您不想将实例保存在 AppDatabase 中,您也可以使用对象(在 Kotlin 中是单例)。

    object AppDatabaseProvider {
        private var INSTANCE: AppDatabase? = null
    
        fun getInMemoryDatabase(context: Context): AppDatabase {
           // ...
        }
    
        fun destroyInstance() {
            INSTANCE = null
        }
    }
    

    这些都是在 Kotlin 中处理静态数据的两个选项,但不会比这更短。

    【讨论】:

      【解决方案2】:

      您的解决方案基本上没有问题。

      使用数组文字是一种选择,正如@Willi Mentzel 所指出的那样,如果您喜欢它的外观,它会使您的代码更短。

      但是,这段获取单例实例的代码是错误的:

      private var INSTANCE: AppDatabase? = null
      
      fun getInMemoryDatabase(context: Context) = INSTANCE ?: Room.inMemoryDatabaseBuilder(context.applicationContext, AppDatabase::class.java).build()
      

      getInMemoryDatabase 函数从不分配值给INSTANCE,这意味着它将永远是null,并且每次调用该函数时,Elvis 运算符的右侧都会被评估并返回。这意味着每次都会创建一个新实例 - 而不是单例,您只需使用此代码创建一个工厂。


      可以使用 Elvis 运算符来稍微缩短您的原始代码:

      fun getInMemoryDatabase(context: Context): AppDatabase {
          INSTANCE = INSTANCE ?: Room.inMemoryDatabaseBuilder(context.applicationContext, AppDatabase::class.java).build()
          return INSTANCE!!
      }
      

      这将在第一个调用之后的每个调用中为自己额外分配INSTANCE,我认为保存这几行可能不值得,因为您的原始代码只有一个常规的空检查是比这更容易阅读。

      【讨论】:

      【解决方案3】:

      可能会有任何提前,尝试如下

      @Database(entities = arrayOf(Book::class, User::class), version = 1)
      abstract class AppDatabase : RoomDatabase() {
      
          abstract fun bookModel() : BookDao
          abstract fun userModel() : UserDao
      
          companion object {
              private var INSTANCE: AppDatabase? = null
      
              fun getInMemoryDatabase(context: Context): AppDatabase {
                  return INSTANCE ?: Room.inMemoryDatabaseBuilder(context, this).build()
              }
      
              fun destroyInstance() {
                  INSTANCE = null
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2019-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-25
        • 1970-01-01
        相关资源
        最近更新 更多