SQLiteOpenHelper
类中有一个onCreate(SQLiteDatabase ...)
方法,我用它来向数据库表中插入一些初始数据。
是否有一种方法可以在首次运行应用程序时将某些数据插入到Room数据库表中?
SQLiteOpenHelper
类中有一个onCreate(SQLiteDatabase ...)
方法,我用它来向数据库表中插入一些初始数据。
是否有一种方法可以在首次运行应用程序时将某些数据插入到Room数据库表中?
更新
有三种方式可以实现此操作:重要:查看此处以获取迁移详细信息
1- 从导出的资产模式填充数据库
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
.createFromAsset("database/myapp.db")
.build();
2- 从文件中填充您的数据库
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
.createFromFile(new File("mypath"))
.build();
3- 您可以使用 RoomDatabase.Callback
在数据库创建后或每次打开数据库时运行脚本,该类可在最新版本的 Room library 中使用。
您需要实现 RoomDatabase.Callback
的 onCreate
和 onOpen
方法,并按下面所示将其添加到 RoomDatabase.Builder
中。
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
}
};
您可以在RoomDatabase.Callback方法中使用Room DAO本身来填充数据库。有关完整的示例,请参见Android分页和Room示例
RoomDatabase.Callback dbCallback = new RoomDatabase.Callback() {
public void onCreate(SupportSQLiteDatabase db) {
Executors.newSingleThreadScheduledExecutor().execute(new Runnable() {
@Override
public void run() {
getYourDB(ctx).yourDAO().insertData(yourDataList);
}
});
}
};
getYourDb
部分添加到了onOpen()
方法中。自然地,这将导致无尽的递归调用。 - Alex Semeniuk请参见第52行和第71行的方法 - 在这里,您可以看到在构建数据库实例之后,下一行调用了一个方法,该方法检查数据库中是否有任何记录(使用DAO),如果它为空,则插入最初的数据(再次使用DAO)。
希望这对任何卡住的人有所帮助:)
创建数据库后,您可以填充表格,确保操作在单独的线程上运行。您可以按照以下类来预先填充第一次的表。
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")
)
}
}
}
我试过多种方法来做这件事,但都没有成功。
首先,我尝试使用“addMigrations”方法向Room添加迁移实现,但发现它只在数据库升级时运行,而不是在创建时运行。
然后,我尝试使用“openHelperFactory”方法将SQLiteOpenHelper实现传递给Room。但是,为了绕过Room的包级访问修饰符,我创建了大量类,但最终放弃了努力。我还尝试了子类化Room的FrameworkSQLiteOpenHelperFactory,但是它的构造函数的包级访问修饰符不支持这一点。
最后,我创建了一个IntentService来填充数据,并从我的Application子类的onCreate方法中调用它。这种方法可行,但更好的解决方案应该是Sinigami在此页面其他地方提到的跟踪器问题即将推出的修复。
Darryl
[2017年7月19日添加]
该问题似乎已在Room 1.0.0 Alpha 5中得到解决。此版本添加了一个回调到RoomDatabase,使您可以在首次创建数据库时执行代码。请参阅:
https://developer.android.com/reference/android/arch/persistence/room/RoomDatabase.Callback.html
@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();
}
有3种预填充数据库的方法
前两种是从资产和文件复制,具体描述可参考这里
第三种方法是在创建数据库后通过编程实现
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()
}
}
}
我也曾为这个问题苦恼,这个解决方案对我很有效:
// 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"
// 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)