Android 房间预填充数据第一次不可见
Android Room Pre-populated Data not visible first time
新安装的应用程序,视图模型未绑定数据。
关闭应用程序并再次打开它会在屏幕上显示数据。
数据预填充有问题还是协程使用不正确?
如果我使用 Flow 代替 LiveData,它会随时随地收集数据并且工作得很好,但它有点慢,因为它在流中发送数据。
另外,为了测试,数据也没有加载 LiveData/Flow。
尝试添加 EspressoIdlingResource
和 IdlingResourcesForDataBinding
作为给定 here
创建房间
@Provides
@Singleton
fun provideAppDatabase(
@ApplicationContext context: Context,
callback: AppDatabaseCallback
): AppDatabase {
return Room
.databaseBuilder(context, AppDatabase::class.java, "database_name")
.addCallback(callback)
.build()
AppDatabaseCallback.kt
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
val data = computePrepopulateData(assets_file_name)
data.forEach { user ->
dao.get().insert(user)
}
}
}
道
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
@Query("SELECT * FROM $table_name")
suspend fun getAllUser(): List<User>
视图模型
CoroutineScope(Dispatchers.IO).launch {
repository.getData().let {
listUser.postValue(it)
}
}
使用 BindingAdapter 附加数据
app:list="@{viewModel.listUser}"
您的 DAO returns suspend fun getAllUser(): List<User>
,这意味着这是一次性的事情。所以当应用程序第一次启动时,数据库初始化没有完成,你得到一个空列表,因为数据库是空的。 运行第二次应用,初始化完成,获取数据
如何修复:
- 将
getAllUser()
切换为 return a Flow
:
// annotations omitted
fun getAllUser(): Flow<List<User>>
- 切换
insertUser
以使用 List
// annotations omitted
suspend fun insertUser(users: List<User>)
此更改的原因是减少了 Flow
发出的次数。每次数据库更改时,Flow
都会发出一个新列表。通过多次插入 List<User>
而不是插入单个 User
,(在第一个 运行 上)Flow
将发出两次(空列表 + 完整列表)一次插入的用户次数。
解决这个问题的另一种方法是使用事务+插入单个用户。
- 我建议你在
ViewModel
中使用 viewModelScope 来启动协同程序,这样当 ViewModel
被销毁时它会被正确取消。
新安装的应用程序,视图模型未绑定数据。 关闭应用程序并再次打开它会在屏幕上显示数据。
数据预填充有问题还是协程使用不正确?
如果我使用 Flow 代替 LiveData,它会随时随地收集数据并且工作得很好,但它有点慢,因为它在流中发送数据。
另外,为了测试,数据也没有加载 LiveData/Flow。
尝试添加 EspressoIdlingResource
和 IdlingResourcesForDataBinding
作为给定 here
创建房间
@Provides
@Singleton
fun provideAppDatabase(
@ApplicationContext context: Context,
callback: AppDatabaseCallback
): AppDatabase {
return Room
.databaseBuilder(context, AppDatabase::class.java, "database_name")
.addCallback(callback)
.build()
AppDatabaseCallback.kt
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
val data = computePrepopulateData(assets_file_name)
data.forEach { user ->
dao.get().insert(user)
}
}
}
道
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
@Query("SELECT * FROM $table_name")
suspend fun getAllUser(): List<User>
视图模型
CoroutineScope(Dispatchers.IO).launch {
repository.getData().let {
listUser.postValue(it)
}
}
使用 BindingAdapter 附加数据
app:list="@{viewModel.listUser}"
您的 DAO returns suspend fun getAllUser(): List<User>
,这意味着这是一次性的事情。所以当应用程序第一次启动时,数据库初始化没有完成,你得到一个空列表,因为数据库是空的。 运行第二次应用,初始化完成,获取数据
如何修复:
- 将
getAllUser()
切换为 return aFlow
:
// annotations omitted
fun getAllUser(): Flow<List<User>>
- 切换
insertUser
以使用List
// annotations omitted
suspend fun insertUser(users: List<User>)
此更改的原因是减少了 Flow
发出的次数。每次数据库更改时,Flow
都会发出一个新列表。通过多次插入 List<User>
而不是插入单个 User
,(在第一个 运行 上)Flow
将发出两次(空列表 + 完整列表)一次插入的用户次数。
解决这个问题的另一种方法是使用事务+插入单个用户。
- 我建议你在
ViewModel
中使用 viewModelScope 来启动协同程序,这样当ViewModel
被销毁时它会被正确取消。