创建数据库时,我使用Room onCreate()回调来初始化一些数据. 使用刀柄:

@Singleton
@Provides
fun provideDatabase(@ApplicationContext applicationContext: Context): AppDatabase {
    return Room.databaseBuilder(applicationContext, AppDatabase::class.java, DATABASE_NAME)
        .allowMainThreadQueries()
        .fallbackToDestructiveMigration()
        .addCallback(object : RoomDatabase.Callback() {
            override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)
                val provideDatabase = provideDatabase(applicationContext)
                provideDatabase.userDao().createUser(LocalUser())
            }
        })
        .build()
}

但我在使用userDao时遇到了例外:

java.nio.channels.OverlappingFileLockException

不知道为什么会发生这种情况,也许我错误地使用了Room+Hilt?

基于这个没有刀柄的教程,它应该毫无例外地工作: https://developermemos.com/posts/prepopulate-android-room-data#google_vignette

推荐答案

当调用onCreate回调时,数据库已经创建.根据再次调用创建 super.onCreate将try 再次创建数据库,创建完全相同的文件,因此遇到锁.

数据库传递给回调,因此为db: SupportSQLiteDatabase

考虑作为一个例子:-

                ....
                .addCallback(object : RoomDatabase.Callback() {
                    override fun onCreate(db: SupportSQLiteDatabase) {
                        //super.onCreate(db)
                        //val provideDatabase = provideDatabase(applicationContext)
                        //provideDatabase.userDao().createUser(LocalUser())
                        DatabaseUtils.dumpCursor(db.query("SELECT * FROM sqlite_master"))
                    }
                })
                .build()

其中,查询模式(SQLite_master)并转储生成的指针(输出到日志(log)).例如,使用上述结果:-

2024-04-17 17:33:55.152 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@68ac7e0
2024-04-17 17:33:55.152 I/System.out: 0 {
2024-04-17 17:33:55.152 I/System.out:    type=table
2024-04-17 17:33:55.152 I/System.out:    name=android_metadata
2024-04-17 17:33:55.152 I/System.out:    tbl_name=android_metadata
2024-04-17 17:33:55.152 I/System.out:    rootpage=3
2024-04-17 17:33:55.152 I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
2024-04-17 17:33:55.153 I/System.out: }
2024-04-17 17:33:55.153 I/System.out: 1 {
2024-04-17 17:33:55.153 I/System.out:    type=table
2024-04-17 17:33:55.153 I/System.out:    name=tasks
2024-04-17 17:33:55.153 I/System.out:    tbl_name=tasks
2024-04-17 17:33:55.153 I/System.out:    rootpage=4
2024-04-17 17:33:55.153 I/System.out:    sql=CREATE TABLE `tasks` (`taskId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)
2024-04-17 17:33:55.153 I/System.out: }
2024-04-17 17:33:55.153 I/System.out: 2 {
2024-04-17 17:33:55.153 I/System.out:    type=table
2024-04-17 17:33:55.153 I/System.out:    name=sqlite_sequence
2024-04-17 17:33:55.153 I/System.out:    tbl_name=sqlite_sequence
2024-04-17 17:33:55.153 I/System.out:    rootpage=5
2024-04-17 17:33:55.153 I/System.out:    sql=CREATE TABLE sqlite_sequence(name,seq)
2024-04-17 17:33:55.153 I/System.out: }
2024-04-17 17:33:55.153 I/System.out: 3 {
2024-04-17 17:33:55.153 I/System.out:    type=table
2024-04-17 17:33:55.153 I/System.out:    name=TaskTaskCR
2024-04-17 17:33:55.153 I/System.out:    tbl_name=TaskTaskCR
2024-04-17 17:33:55.153 I/System.out:    rootpage=6
2024-04-17 17:33:55.153 I/System.out:    sql=CREATE TABLE `TaskTaskCR` (`parentTaskId` INTEGER NOT NULL, `childTaskId` INTEGER NOT NULL, PRIMARY KEY(`parentTaskId`, `childTaskId`))
2024-04-17 17:33:55.153 I/System.out: }
2024-04-17 17:33:55.153 I/System.out: 4 {
2024-04-17 17:33:55.153 I/System.out:    type=index
2024-04-17 17:33:55.153 I/System.out:    name=sqlite_autoindex_TaskTaskCR_1
2024-04-17 17:33:55.153 I/System.out:    tbl_name=TaskTaskCR
2024-04-17 17:33:55.153 I/System.out:    rootpage=7
2024-04-17 17:33:55.154 I/System.out:    sql=null
2024-04-17 17:33:55.154 I/System.out: }
2024-04-17 17:33:55.154 I/System.out: 5 {
2024-04-17 17:33:55.154 I/System.out:    type=table
2024-04-17 17:33:55.154 I/System.out:    name=room_master_table
2024-04-17 17:33:55.154 I/System.out:    tbl_name=room_master_table
2024-04-17 17:33:55.154 I/System.out:    rootpage=8
2024-04-17 17:33:55.154 I/System.out:    sql=CREATE TABLE room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)
2024-04-17 17:33:55.154 I/System.out: }
2024-04-17 17:33:55.154 I/System.out: <<<<<

即,可以看出,数据库由以下内容组成:-

  • 100*(包含区域设置的Android特定系统表)
  • 101(按照@Entity注释类的应用表)
  • 100(由于使用了AutoINCREMENT,因此SQLite系统表)
  • 101(按照@Entity注释类的应用表)
  • 索引100(由SQLite自动生成)
  • 100(包含模式哈希值的Room表,用于判断模式是否已更改)

What you should be doing is utilising the passed SupportSQLiteDatabase to initialise the data.这就是它被传递给回调的原因.

例如db.execSQL("INSERT INTO tasks (name) VALUES('Task001')")

  • 显然,这适合用于此答案的数据库,并且很可能不是您要使用的数据库.

使用上面的内容和额外的行,然后应用程序判断,运行后显示:-

enter image description here

  • 即该行已添加
    • 其他行稍后添加,因为演示使用了之前答案中未更改的代码.

Android相关问答推荐

如何自定义所选的NavigationBar项目?

理解修饰符<;方法>;与修饰符<;方法>;:效果和行为解释(Android开发者Jetpack Compose)

Android 14无法删除已配置的文件

请求标头为空/无法通过拦截器获取

用于小部件泄漏警告的伙伴对象中的Kotlin Lateinit

从惰性列中删除项目时Jetpack Compose崩溃

在 Compose 中,当用户持续向下滚动时,LazyColumn 不会显示新项目

Camera2 将图像从 ImageReader 传递到 MediaRecorder

在本地通知中设置自定义声音

为什么我收到这个错误我需要安装 android studio

我如何比较多个时间范围并在 Android Compose 中并排显示它们

如何在Android中使用嵌套的Recyclerview

在 compose android 中创建一个圆形按钮和居中文本

延时kotlin中时分秒的使用方法

我该怎么做文本计时器

Kotlin Coroutines 会取代 AsyncTask 吗?

从expose 的 dropdownMenu 可组合、jetpack 组合中 Select 选项时,不会触发文本字段的 onValueChange

Jetpack 使用 Canvas 组成半圆

compose FontFamily 错误:必须初始化变量

Android:在模块 jetified-play-services-measurement 和 jetified-play-services-measurement-impl 中发现重复类