簡體   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