如何在首次运行时填充Android Room数据库表?

时间:2017-06-22 10:58:14

标签: android android-room

SQLiteOpenHelper中有一个onCreate(SQLiteDatabase ...)方法,我用它来填充一些初始数据的数据库表。

  

有没有办法首先在Room数据库表中插入一些数据   app run?

7 个答案:

答案 0 :(得分:72)

您可以在创建数据库后运行脚本,也可以在每次使用RoomDatabase.Callback打开数据库时运行脚本,此类可在最新版本的Room库中使用。

您需要实施onCreate的{​​{1}}和onOpen方法,并将其添加到RoomDatabase.Callback,如下所示。

RoomDatabase.Builder

Reference

您可以在RoomDatabase.Callback方法中使用Room DAO来填充数据库。有关完整示例,请参阅Pagination and Room example

yourDatabase = Room.databaseBuilder(context, YourDatabase.class, "your db")
    .addCallback(rdc)
    .build();

RoomDatabase.Callback rdc = new RoomDatabase.Callback() {
    public void onCreate (SupportSQLiteDatabase db) {
        // do something after database has been created
    }
    public void onOpen (SupportSQLiteDatabase db) {
        // do something every time database is open
    }
};

答案 1 :(得分:9)

我尝试按照Arnav Rao的建议使用RoomDatabase.Callback,但是要使用回调,您不能使用DAO,因为在建立数据库之前已创建了回调。您可以使用db.insert和content值,但是我认为那是不正确的。因此,在进行了更多研究之后-我花了好几年的时间-但在浏览Google提供的示例时,我实际上找到了答案。

https://github.com/googlesamples/android-architecture-components/blob/master/PersistenceContentProviderSample/app/src/main/java/com/example/android/contentprovidersample/data/SampleDatabase.java

请参见第52行和第71行的方法-在其中,您可以看到在构建数据库实例之后,下一行将调用一个方法,该方法检查数据库中是否有任何记录(使用DAO),然后检查它为空,将插入初始数据(再次使用DAO)。

希望这对陷入困境的其他人有所帮助:)

答案 2 :(得分:5)

我尝试了很多方法来做到这一点,每个方法都没有。

首先,我尝试使用' addMigrations'添加迁移实施到Room。方法,但发现它只在数据库升级期间运行,而不是在创建时运行。

然后,我尝试使用' openHelperFactory'将SQLiteOpenHelper实现传递给Room。方法。但是在创建了一堆类以便绕过Room的包级访问修饰符之后,我放弃了努力。我还尝试了对Room的FrameworkSQLiteOpenHelperFactory进行子类化,但同样,其构造函数的包级访问修饰符并不支持此功能。

最后,我创建了一个IntentService来填充数据,并从我的Application子类的onCreate方法调用它。该方法有效但更好的解决方案应该是本页其他地方Sinigami提到的跟踪器问题的即将到来的解决方案。

的Darryl

[2017年7月19日添加]

问题看起来好像已经在1.0.0室解决了。 Alpha 5.此版本添加了对RoomDatabase的回调,允许您在首次创建数据库时执行代码。看看:

https://developer.android.com/reference/android/arch/persistence/room/RoomDatabase.Callback.html

答案 3 :(得分:1)

@Provides
@Singleton
LocalDatabase provideLocalDatabase(@DatabaseInfo String dbName, Context context) {
    return Room.databaseBuilder(context, LocalDatabase.class, dbName)
            .addCallback(new RoomDatabase.Callback() {
                @Override
                public void onCreate(@NonNull SupportSQLiteDatabase db) {
                    super.onCreate(db);
                    db.execSQL("INSERT INTO id_generator VALUES(1, 1, 1);");
                }
            })
//                .addMigrations(LocalDatabase.MIGRATION_1_2)
            .build();
}

答案 4 :(得分:1)

您可以在创建数据库后填充表,确保操作在单独的线程上运行。您可以按照下面的课程在第一时间预填充表格。

AppDatabase.kt

@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {

    abstract fun userDao(): UserDao

    companion object {

        // For Singleton instantiation
        @Volatile private var instance: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return instance ?: synchronized(this) {
                instance ?: buildDatabase(context).also { instance = it }
            }
        }

        private fun buildDatabase(context: Context): AppDatabase {
            return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
                    .addCallback(object : RoomDatabase.Callback() {
                        override fun onCreate(db: SupportSQLiteDatabase) {
                            super.onCreate(db)
                            //pre-populate data
                            Executors.newSingleThreadExecutor().execute {
                                instance?.let {
                                    it.userDao().insertUsers(DataGenerator.getUsers())
                                }
                            }
                        }
                    })
                    .build()
        }
    }
}

DataGenerator.kt

class DataGenerator {

    companion object {
        fun getUsers(): List<User>{
            return listOf(
                User(1, "Noman"),
                User(2, "Aayan"),
                User(3, "Tariqul")
            )
        }
    }

}

答案 5 :(得分:1)

3种方法预填充数据库
前2个是针对资产和文件的处理,here
第三种方法是在数据库创建后以编程方式进行

Room.databaseBuilder(context, Database::class.java, "app.db")
    // ...
    // 1
    .createFromAsset(...)
    // 2
    .createFromFile(...)
    // 3
    .addCallback(DatabaseCallback())
    .build()

这是手动填充

class DatabaseCallback : RoomDatabase.Callback() {

    override fun onCreate(db: SupportSQLiteDatabase) = db.run {
        // Notice non-ui thread is here
        beginTransaction()
        try {
            execSQL(...)
            insert(...)
            update(...)
            delete(...)
            setTransactionSuccessful()
        } finally {
            endTransaction()
        }
    }
}

答案 6 :(得分:0)

我也在这个主题上苦苦挣扎,这个解决方案对我有用:

// build.gradle

    def room_version = "2.2.5"

    // Room
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
    implementation "androidx.room:room-ktx:$room_version"

在您的App类中:

// virtually create the db
        val db = Room.databaseBuilder(
            appContext, AppDatabase::class.java,
            Res.getString(R.string.dbname)
        ).createFromAsset(Res.getString(R.string.source_db_name)).build()

        // first call to db really creates the db on filesystem
        db.query("SELECT * FROM " + Room.MASTER_TABLE_NAME, null)