[英]RoomDatabase onCreate called twice
I am using the RoomDatabase.Callback
to populate the database when onCreate
is called. 调用
onCreate
时,我正在使用RoomDatabase.Callback
填充数据库。 According to the documentation, this method should only be called once when the database is first created. 根据文档,此方法仅应在首次创建数据库时调用一次 。
Called when the database is created for the first time.
首次创建数据库时调用。 This is called after all the tables are created.
创建所有表后将调用此方法。
But for some reason it is being called twice (sometimes more than twice). 但是由于某种原因,它被两次调用(有时超过两次)。 This wouldn't be too much of an issue it the data was being replaced on the second call, but because each call starts a new thread with separate input calls it is creating duplicate data.
如果在第二次调用中替换了数据,这并不是什么大问题,但是由于每个调用都使用单独的输入调用启动了一个新线程,因此它正在创建重复数据。
This is the database in question. 这是有问题的数据库。
@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)
}
}
}
I am doing some strange things in order to add FTS support, but that shouldn't cause onCreate()
to be called twice; 为了增加对FTS的支持,我在做一些奇怪的事情,但这不应该导致
onCreate()
被调用两次。 especially considering I do the same thing in another database, which doesn't cause the same issue. 特别是考虑到我在另一个数据库中执行相同的操作,这不会导致相同的问题。
@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)
}
}
}
I add the callback to the database in a separate repository class. 我在单独的存储库类中将回调添加到数据库。
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
}
I cannot figure out why this would be the case, especially considering it only happens to one of my two (very similar) implementations. 我无法弄清楚为什么会这样,尤其是考虑到它仅发生在我的两个(非常相似)实现中之一。
There is a chance that the class DirectoryRepository
instantiated more than once and the callback added on each init
invocation. class DirectoryRepository
有可能多次实例化,并且在每次init
调用时都会添加回调。
Besides that, you should add callbacks with addCallback()
provided by the builder of the RoomDatabase
class. 除此之外,您应该使用
RoomDatabase
类的构建器提供的addCallback()
添加回调。
Otherwise, you might face with an opposite issue, that a callback won't fired at all. 否则,您可能会面临相反的问题,即根本不会触发回调。 This can happen if you manually add a callback after
SupportSQLiteOpenHelper
created in <database-class>_Impl.createOpenHelper(...)
method. 如果在
<database-class>_Impl.createOpenHelper(...)
方法中创建的SupportSQLiteOpenHelper
之后手动添加回调,则会发生这种情况。
You should check for instance == null
even in the synchronized block. 即使在同步块中,也应检查
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
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.