调用RoomDatabase.Callback
时,我正在使用onCreate
填充数据库。根据文档,此方法仅在首次创建数据库时才被称为一次。
在首次创建数据库时调用。这就是所谓的 在创建所有表之后。
但是由于某种原因,它被两次调用(有时超过两次)。如果在第二次调用中替换了数据,这不会有太大的问题,但是由于每个调用都使用单独的输入调用启动了一个新线程,因此会创建重复的数据。
这是有问题的数据库。
@Database(entities = [FTSPlaceholder::class], version = 1)
abstract class DirectoryDatabase : RoomDatabase() {
companion object {
const val NAME = "directory_database"
@Volatile private var INSTANCE: DirectoryDatabase? = null
fun getInstance(context: Context): DirectoryDatabase = INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
private fun buildDatabase(context: Context): DirectoryDatabase =
Room.databaseBuilder(context.applicationContext, DirectoryDatabase::class.java, NAME)
.addCallback(FTSCallback()).build()
}
fun addCallback(callback: Callback) {
if (mCallbacks == null) mCallbacks = ArrayList()
mCallbacks?.add(callback)
}
abstract fun departmentDao(): DepartmentDao
abstract fun employeeDao(): EmployeeDao
private class FTSCallback : Callback() {
companion object {
private const val CREATE_TABLE_DEPARTMENTS =
"CREATE VIRTUAL TABLE IF NOT EXISTS `departments` " +
"USING FTS4(`code` TEXT NOT NULL, `title` TEXT NOT NULL, " +
"`location` TEXT NOT NULL, `phone` TEXT, `fax` TEXT, PRIMARY KEY(`code`))"
private const val CREATE_TABLE_PERSONNEL =
"CREATE VIRTUAL TABLE IF NOT EXISTS `personnel` " +
"USING FTS4(`familyName` TEXT NOT NULL, `givenName` TEXT NOT NULL, " +
"`middleName` TEXT, `title` TEXT NOT NULL, `location` TEXT NOT NULL, " +
"`room` TEXT NOT NULL, `phone1` TEXT NOT NULL, `phone2` TEXT NOT NULL, " +
"`email` TEXT NOT NULL, `fax` TEXT, `department` TEXT NOT NULL, " +
"`school` TEXT, PRIMARY KEY(`familyName`, `givenName`, `title`))"
}
override fun onCreate(db: SupportSQLiteDatabase) {
db.execSQL(CREATE_TABLE_DEPARTMENTS)
db.execSQL(CREATE_TABLE_PERSONNEL)
}
}
}
为了添加FTS支持,我正在做一些奇怪的事情,但这不应导致onCreate()
被调用两次;特别是考虑到我在另一个数据库中执行相同的操作,不会导致相同的问题。
@Database(entities = [Area::class], version = 1)
abstract class MapDatabase : RoomDatabase() {
companion object {
const val NAME = "map_database"
@Volatile private var INSTANCE: MapDatabase? = null
fun getInstance(context: Context): MapDatabase = INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
private fun buildDatabase(context: Context): MapDatabase =
Room.databaseBuilder(context.applicationContext, MapDatabase::class.java, NAME)
.addCallback(FTSCallback()).build()
}
fun addCallback(callback: Callback) {
if (mCallbacks == null) mCallbacks = ArrayList()
mCallbacks?.add(callback)
}
abstract fun placeDao(): PlaceDao
abstract fun areaDao(): AreaDao
private class FTSCallback : Callback() {
companion object {
private const val CREATE_TABLE_PLACES =
"CREATE VIRTUAL TABLE IF NOT EXISTS `places` " +
"USING FTS4(`id` INTEGER NOT NULL, `title` TEXT NOT NULL, " +
"`subtitle` TEXT, `description` TEXT, `latitude` REAL NOT NULL, " +
"`longitude` REAL NOT NULL, `type` INTEGER NOT NULL, " +
"`parent` INTEGER, PRIMARY KEY(`id`))"
}
override fun onCreate(db: SupportSQLiteDatabase) {
db.execSQL(CREATE_TABLE_PLACES)
}
}
}
我在单独的存储库类中将回调添加到数据库中。
class DirectoryRepository(application: Application) {
private val database = DirectoryDatabase.getInstance(application)
init {
database.addCallback(object : RoomDatabase.Callback() {
// This method is being called twice
override fun onCreate(db: SupportSQLiteDatabase) {
refresh()
}
}
}
// Code omitted for brevity
}
我不知道为什么会这样,尤其是考虑到它仅发生在我的两个(非常相似)实现中的一个。
答案 0 :(得分:1)
class DirectoryRepository
可能会多次实例化,并且每次init
调用都会添加回调。
除此之外,您还应该添加addCallback()
类的生成器提供的RoomDatabase
回调。
否则,您可能会面临相反的问题,即根本不会触发回调。如果您在通过SupportSQLiteOpenHelper
方法创建的<database-class>_Impl.createOpenHelper(...)
之后手动添加了回调,则会发生这种情况。
答案 1 :(得分:0)
即使在同步块中,您也应检查instance == null
。
fun getInstance(context: Context): DirectoryDatabase {
return INSTANCE ?: synchronized(this) {
if(INSTANCE != null) {
return@synchronized database
}
val database = Room.databaseBuilder(context.applicationContext,
DirectoryDatabase::class.java, NAME)
.addCallback(FTSCallback())
.build()
INSTANCE = database
return@synchronized database
}
}