Android 房间预填充数据第一次不可见

Android Room Pre-populated Data not visible first time

新安装的应用程序,视图模型未绑定数据。 关闭应用程序并再次打开它会在屏幕上显示数据。

数据预填充有问题还是协程使用不正确?

如果我使用 Flow 代替 LiveData,它会随时随地收集数据并且工作得很好,但它有点慢,因为它在流中发送数据。

另外,为了测试,数据也没有加载 LiveData/Flow。 尝试添加 EspressoIdlingResourceIdlingResourcesForDataBinding 作为给定 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>,这意味着这是一次性的事情。所以当应用程序第一次启动时,数据库初始化没有完成,你得到一个空列表,因为数据库是空的。 运行第二次应用,初始化完成,获取数据

如何修复:

  1. getAllUser() 切换为 return a Flow:
// annotations omitted
fun getAllUser(): Flow<List<User>>
  1. 切换 insertUser 以使用 List
// annotations omitted
suspend fun insertUser(users: List<User>)

此更改的原因是减少了 Flow 发出的次数。每次数据库更改时,Flow 都会发出一个新列表。通过多次插入 List<User> 而不是插入单个 User,(在第一个 运行 上)Flow 将发出两次(空列表 + 完整列表)一次插入的用户次数。

解决这个问题的另一种方法是使用事务+插入单个用户。

  1. 我建议你在 ViewModel 中使用 viewModelScope 来启动协同程序,这样当 ViewModel 被销毁时它会被正确取消。