Freshly installing the app, the view model doesn't bind the data. Closing the app and opening it again shows the data on the screen.
Is there any problem with the pre-population of data or is the use of coroutine is not correct?
If I use Flow in place of LiveData, it collects the data on the go and works completely fine, but its a bit slow as it is emitting data in the stream.
Also, for testing, The data didn't load either LiveData/Flow.
Tried adding the EspressoIdlingResource
and IdlingResourcesForDataBinding
as given here
@Provides
@Singleton
fun provideAppDatabase(
@ApplicationContext context: Context,
callback: AppDatabaseCallback
): AppDatabase {
return Room
.databaseBuilder(context, AppDatabase::class.java, "database_name")
.addCallback(callback)
.build()
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)
}
}
app:list="@{viewModel.listUser}"
Your DAO returns suspend fun getAllUser(): List<User>
, meaning it's a one time thing. So when the app starts the first time, the DB initialization is not complete, and you get an empty list because the DB is empty. Running the app the second time, the initialization is complete so you get the data.
How to fix it:
getAllUser()
to return a Flow
:// annotations omitted
fun getAllUser(): Flow<List<User>>
insertUser
to use a List
// annotations omitted
suspend fun insertUser(users: List<User>)
The reason for this change is reducing the number of times the Flow
will emit. Every time the DB changes, the Flow
will emit a new list. By inserting a List<User>
instead of inserting a single User
many times the (on the first run) Flow
will emit twice (an empty list + the full list) compared to number of user times with a single insert.
Another way to solve this issue is to use a transaction + insert a single user.
ViewModel
to launch coroutines so it's properly canceled when the ViewModel
is destroyed.