繁体   English   中英

RoomDatabase onCreate调用了两次

[英]RoomDatabase onCreate called twice

调用onCreate时,我正在使用RoomDatabase.Callback填充数据库。 根据文档,此方法仅应在首次创建数据库时调用一次

首次创建数据库时调用。 创建所有表后将调用此方法。

但是由于某种原因,它被两次调用(有时超过两次)。 如果在第二次调用中替换了数据,这并不是什么大问题,但是由于每个调用都使用单独的输入调用启动了一个新线程,因此它正在创建重复数据。

这是有问题的数据库。

@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

}

我无法弄清楚为什么会这样,尤其是考虑到它仅发生在我的两个(非常相似)实现中之一。

class DirectoryRepository有可能多次实例化,并且在每次init调用时都会添加回调。


除此之外,您应该使用RoomDatabase类的构建器提供的addCallback()添加回调。

否则,您可能会面临相反的问题,即根本不会触发回调。 如果在<database-class>_Impl.createOpenHelper(...)方法中创建的SupportSQLiteOpenHelper之后手动添加回调,则会发生这种情况。

即使在同步块中,也应检查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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM