hum*_*zed 8 singleton android kotlin android-room
我正在尝试使用Room作为单身人士,所以我不必再调用Room.databaseBuilder()- 这是昂贵的 - 不止一次.
@Database(entities = arrayOf(
Price::class,
StationOrder::class,
TicketPrice::class,
Train::class,
TrainCategory::class
), version = 2)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun dao(): TrainDao
companion object {
fun createDatabase(context: Context): AppDatabase
= Room.databaseBuilder(context, AppDatabase::class.java, "trains.db").build()
}
}
Run Code Online (Sandbox Code Playgroud)
注意:
abstract class.Context作为一个论点.我查看了所有类似的StackOverflow问题,但没有一个满足我的要求
在Kotlin中使用参数的Singleton 不是线程安全的
Kotlin - 在Android中转换Singleton DatabaseController的最佳方法 不是线程安全的
Kotlin线程使用参数 使用对象保存本机惰性单例
我找到了解决方案,所以这是将来我和任何可能遇到相同问题的人的答案。
经过研究,我发现我有两个选择。
所以我考虑实现其中之一,但这在kotlin中感觉不对,因为样板代码太多了:p
因此,在进行了更多研究之后,我偶然发现了这篇出色的文章,该文章提供了一种出色的解决方案,该解决方案使用有效的方式使用了双重检查锁定。
我的代码变成这样:
companion object : SingletonHolder<AppDatabase, Context>({
Room.databaseBuilder(it, AppDatabase::class.java, "train.db").build()
})
Run Code Online (Sandbox Code Playgroud)
从文章:
可重用的Kotlin实现:
我们可以封装逻辑以懒散地创建和初始化带有
SingletonHolder类内部参数的单例 。为了使该逻辑线程安全,我们需要实现一种同步算法,而最有效的算法是“双重检查锁定算法”,这也是最难解决的问题。
open class SingletonHolder<T, A>(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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
额外: 如果您要让Singleton有两个参数
open class SingletonHolder2<out T, in A, in B>(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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这种特殊情况下我会诉诸使用匕首2,或其他一些依赖注入库像孝允或牙签。所有这三个库都允许以单例形式提供依赖关系。
这是Dagger 2模块的代码:
@Module
class AppModule constructor(private val context: Context) {
@Provides
@Singleton
fun providesDatabase(): AppDatabase {
return Room.databaseBuilder(
context,
AppDatabase::class.java,
"train.db")
.build()
}
}
Run Code Online (Sandbox Code Playgroud)
AppComponent:
@Singleton
@Component(modules = arrayOf(
AppModule::class
))
interface AppComponent {
fun inject(viewModel: YourViewModel)
fun inject(repository: YourRepository)
}
Run Code Online (Sandbox Code Playgroud)
提供注入的应用程序类:
class App : Application() {
companion object {
private lateinit var appComponent: AppComponent
val component: AppComponent get() = appComponent
}
override fun onCreate() {
super.onCreate()
initializeDagger()
}
private fun initializeDagger() {
component = DaggerAppComponent.builder()
.appModule(AppModule(this))
.build()
}
}
Run Code Online (Sandbox Code Playgroud)
然后将数据库作为单例注入到您需要的任何位置(例如,在应用程序的存储库中):
@Inject lateinit var appDatabase: AppDatabase
init {
App.component.inject(this)
}
Run Code Online (Sandbox Code Playgroud)
使用@Volatile来保证线程安全。
public abstract class AppDatabase : RoomDatabase() {
abstract fun trainDao(): trainDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): Db = INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase ::class.java,
"train-db"
).build()
INSTANCE = instance
instance
}
}
}
Run Code Online (Sandbox Code Playgroud)
摘自: https: //developer.android.com/codelabs/android-room-with-a-view-kotlin#7
| 归档时间: |
|
| 查看次数: |
4941 次 |
| 最近记录: |