(Android) Room 数据库中的初始数据是什么时候存储的?
(Android) When is the initial data stored in the Room database?
我目前正在尝试在 Room database
中设置一些初始数据。
结果,初始数据设置成功,但App Inspection
确认只有在getWorkoutList()
时才保存数据。
更详细地解释一下,初始数据不是单独用插入函数保存的,只有当调用名为getWorkoutList()
的DB数据的函数被执行时,初始数据才会保存在DB中ViewModel
.
在视图模型中创建数据库时,我希望仅使用插入函数保存初始数据。但事实并非如此。
为什么只有insert函数不能保存初始数据?
以下是根据函数调用在App检查中的DB状态。
1.当只执行insertWorkoutList(data)
时
- 没有
DB and table
创建,也没有保存初始数据。
2。当只执行getWokroutList()
时。
- DB 和 table 已创建,但没有数据。
3。当两者都执行时。
- 初始数据正常保存
代码
道
@Dao
interface WorkoutListDao {
@Query("SELECT * FROM WorkoutList")
suspend fun getWorkoutList() : WorkoutList
@Insert
suspend fun insertWorkoutList(workoutList: WorkoutList)
}
锻炼列表数据库
@Database(
entities = [WorkoutList::class],
version = 1
)
@TypeConverters(WorkoutListTypeConverter::class)
abstract class WorkoutListDatabase : RoomDatabase() {
abstract fun workoutListDao() : WorkoutListDao
companion object {
private var INSTANCE : WorkoutListDatabase? = null
@Synchronized
fun getDatabase(context: Context) : WorkoutListDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
WorkoutListDatabase::class.java,
"workoutlist_db"
)
.addCallback(WorkoutListCallback(context))
.build()
INSTANCE = instance
instance
}
}
}
}
WorkoutListCallback
class WorkoutListCallback(private val context: Context) : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
fillWithStartingWorkoutList(context)
}
}
private fun fillWithStartingWorkoutList(context: Context) {
val dao = WorkoutListDatabase.getDatabase(context).workoutListDao()
try {
val data = loadJsonData(context)
// dao.insertWorkoutList(data)
} catch (e: JSONException) {
e.printStackTrace()
}
}
private fun loadJsonData(context: Context) : WorkoutList {
val assetManager = context.assets
val inputStream = assetManager.open(WORKOUTLIST_JSON_FILE)
BufferedReader(inputStream.reader()).use { reader ->
val gson = Gson()
return gson.fromJson(reader, WorkoutList::class.java)
}
}
}
ViewModel
class WorkoutListViewModel(application: Application) : AndroidViewModel(application) {
private val workoutDao = WorkoutListDatabase.getDatabase(application).workoutListDao()
private val workoutListRepo = WorkoutListRepository(workoutDao)
fun setList(part : BodyPart) {
viewModelScope.launch(Dispatchers.IO) {
workoutListRepo.getWorkoutList()
}
}
}
只有在实际访问数据库时才会调用回调,而不是在获得注解为 class 的 @Database 实例时调用。
因此数据库不是由以下人员创建的:-
val dao = WorkoutListDatabase.getDatabase(context).workoutListDao()
但由
创建
workoutListRepo.getWorkoutList()
那是打开数据库的实际相对耗费资源的操作,留到绝对需要时才使用。
绕过可能是使用:-
fun getDatabase(context: Context) : WorkoutListDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
WorkoutListDatabase::class.java,
"workoutlist_db"
)
.addCallback(WorkoutListCallback(context))
.build()
INSTANCE = instance
instance.getOpenHelper().getWritableDatabase() //<<<<< FORCE OPEN
instance
}
}
这将强制打开数据库,如果它实际上不存在,则将调用覆盖的 onCreate
方法。 然而,这(我认为)将在主线程上完成,这是您不希望的。
我强烈建议不要使用带有注释的@Dao class(es) 中的函数,特别是如果它们已挂起,因为您可能无法控制线程何时 运行.
您应该使用 SupportSQLiteDatabase passed to the function, it has many methods e.g. you would likely use the insert 方法。
有关订单有问题的示例,请参阅 ROOM database: insert static data before other CRUD operations。该示例包括转换操作以利用预期的 SupportSQLiteDatabase 方法。
您可能会注意到该示例包括将所有数据库更改放入单个事务中,这比将每个单独的操作(示例中的insert/delete)写入磁盘更有效,整个事务(所有动作)都写入磁盘一次。
我目前正在尝试在 Room database
中设置一些初始数据。
结果,初始数据设置成功,但App Inspection
确认只有在getWorkoutList()
时才保存数据。
更详细地解释一下,初始数据不是单独用插入函数保存的,只有当调用名为getWorkoutList()
的DB数据的函数被执行时,初始数据才会保存在DB中ViewModel
.
在视图模型中创建数据库时,我希望仅使用插入函数保存初始数据。但事实并非如此。
为什么只有insert函数不能保存初始数据?
以下是根据函数调用在App检查中的DB状态。
1.当只执行insertWorkoutList(data)
时
- 没有
DB and table
创建,也没有保存初始数据。
2。当只执行getWokroutList()
时。
- DB 和 table 已创建,但没有数据。
3。当两者都执行时。
- 初始数据正常保存
代码
道
@Dao
interface WorkoutListDao {
@Query("SELECT * FROM WorkoutList")
suspend fun getWorkoutList() : WorkoutList
@Insert
suspend fun insertWorkoutList(workoutList: WorkoutList)
}
锻炼列表数据库
@Database(
entities = [WorkoutList::class],
version = 1
)
@TypeConverters(WorkoutListTypeConverter::class)
abstract class WorkoutListDatabase : RoomDatabase() {
abstract fun workoutListDao() : WorkoutListDao
companion object {
private var INSTANCE : WorkoutListDatabase? = null
@Synchronized
fun getDatabase(context: Context) : WorkoutListDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
WorkoutListDatabase::class.java,
"workoutlist_db"
)
.addCallback(WorkoutListCallback(context))
.build()
INSTANCE = instance
instance
}
}
}
}
WorkoutListCallback
class WorkoutListCallback(private val context: Context) : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
fillWithStartingWorkoutList(context)
}
}
private fun fillWithStartingWorkoutList(context: Context) {
val dao = WorkoutListDatabase.getDatabase(context).workoutListDao()
try {
val data = loadJsonData(context)
// dao.insertWorkoutList(data)
} catch (e: JSONException) {
e.printStackTrace()
}
}
private fun loadJsonData(context: Context) : WorkoutList {
val assetManager = context.assets
val inputStream = assetManager.open(WORKOUTLIST_JSON_FILE)
BufferedReader(inputStream.reader()).use { reader ->
val gson = Gson()
return gson.fromJson(reader, WorkoutList::class.java)
}
}
}
ViewModel
class WorkoutListViewModel(application: Application) : AndroidViewModel(application) {
private val workoutDao = WorkoutListDatabase.getDatabase(application).workoutListDao()
private val workoutListRepo = WorkoutListRepository(workoutDao)
fun setList(part : BodyPart) {
viewModelScope.launch(Dispatchers.IO) {
workoutListRepo.getWorkoutList()
}
}
}
只有在实际访问数据库时才会调用回调,而不是在获得注解为 class 的 @Database 实例时调用。
因此数据库不是由以下人员创建的:-
val dao = WorkoutListDatabase.getDatabase(context).workoutListDao()
但由
创建workoutListRepo.getWorkoutList()
那是打开数据库的实际相对耗费资源的操作,留到绝对需要时才使用。
绕过可能是使用:-
fun getDatabase(context: Context) : WorkoutListDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
WorkoutListDatabase::class.java,
"workoutlist_db"
)
.addCallback(WorkoutListCallback(context))
.build()
INSTANCE = instance
instance.getOpenHelper().getWritableDatabase() //<<<<< FORCE OPEN
instance
}
}
这将强制打开数据库,如果它实际上不存在,则将调用覆盖的 onCreate
方法。 然而,这(我认为)将在主线程上完成,这是您不希望的。
我强烈建议不要使用带有注释的@Dao class(es) 中的函数,特别是如果它们已挂起,因为您可能无法控制线程何时 运行.
您应该使用 SupportSQLiteDatabase passed to the function, it has many methods e.g. you would likely use the insert 方法。
有关订单有问题的示例,请参阅 ROOM database: insert static data before other CRUD operations。该示例包括转换操作以利用预期的 SupportSQLiteDatabase 方法。
您可能会注意到该示例包括将所有数据库更改放入单个事务中,这比将每个单独的操作(示例中的insert/delete)写入磁盘更有效,整个事务(所有动作)都写入磁盘一次。