RoomDatabase onCreate 调用了两次
RoomDatabase onCreate called twice
我正在使用RoomDatabase.Callback
to populate the database when onCreate
调用。根据文档,首次创建数据库时,只应调用此方法一次。
Called when the database is created for the first time. This is called
after all the tables are created.
但由于某种原因它被调用了两次(有时超过两次)。如果数据在第二次调用时被替换,这不会是一个太大的问题,但是因为每次调用都会启动一个具有单独输入调用的新线程,所以它会创建重复数据。
这是有问题的数据库。
@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。
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
}
我不明白为什么会这样,特别是考虑到它只发生在我的两个(非常相似的)实现之一上。
即使在同步块中,您也应该检查 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
}
}
class DirectoryRepository
有可能多次实例化并且在每次 init
调用时添加回调。
除此之外,您应该使用 RoomDatabase
class.
的构建器提供的 addCallback()
添加回调
否则,您可能会遇到相反的问题,即根本不会触发回调。如果您在 <database-class>_Impl.createOpenHelper(...)
方法中创建 SupportSQLiteOpenHelper
之后手动添加回调,就会发生这种情况。
我正在使用RoomDatabase.Callback
to populate the database when onCreate
调用。根据文档,首次创建数据库时,只应调用此方法一次。
Called when the database is created for the first time. This is called after all the tables are created.
但由于某种原因它被调用了两次(有时超过两次)。如果数据在第二次调用时被替换,这不会是一个太大的问题,但是因为每次调用都会启动一个具有单独输入调用的新线程,所以它会创建重复数据。
这是有问题的数据库。
@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。
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
}
我不明白为什么会这样,特别是考虑到它只发生在我的两个(非常相似的)实现之一上。
即使在同步块中,您也应该检查 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
}
}
class DirectoryRepository
有可能多次实例化并且在每次 init
调用时添加回调。
除此之外,您应该使用 RoomDatabase
class.
addCallback()
添加回调
否则,您可能会遇到相反的问题,即根本不会触发回调。如果您在 <database-class>_Impl.createOpenHelper(...)
方法中创建 SupportSQLiteOpenHelper
之后手动添加回调,就会发生这种情况。