'How can I observe a table in Room and get entities from other tables based on updates?
I want to use Coroutine flows to achieve this.
I have a DAO/Table in Room: info. This info-table is a lookup that holds id and type for other models. There's a table per type [A, B, C] and the id (PrimaryKey) in the info-table and corresponding type-table are the same.
If I declare a getAll query in the info DAO, I can observe it in a ViewModel and any updates to the table would propagate to the collector
@Query("SELECT * FROM $INFO_TABLE WHERE")
fun getAll(): Flow<List<Info>>
In my "database-class" that have access to all dao I do:
fun getModels(): Flow<List<Model>> {
return infoDao.getAll()
.onEach { Timber.d("Info (${it.size})") }
.flatMapConcat { list ->
val flows = list.map { getModel(it.id, it.type) }
combine(flows) {
Timber.d("Combine (${it.size})")
it.toList()
}
}
The getModel(id, type) returns a Flow from that types dao.
Expected / wanted behaviour:
- When a info-model is inserted into the info-dao, the
getAll().onEach{ }is called - When the info table gets updated, the Flow<List> emits a new (updated) list.
Actual behaviour:
- The
onEachfor the InfoDao is only ever called once, even when the info table is modified. - The log in combine is called when info is updated, but with the same
it.size
What's wrong, how do I fix this?
How do I chain Flows in this manner?
How can I get the getAll() flow to be "re-triggered"?
Solution 1:[1]
I managed to get something working, but I would love to hear what's going on and the theory behind it.
(Also, I thought of having a solution with one Flow from the info-table, and simple suspend functions from the model-table but it felt less appealing)
override fun getAllModel(): Flow<List<Model>> = infoDao.getAll()
.onEach { Timber.d("Info (${it.size})") }
.map { list -> list.map { info -> getModel(info.id, info.type) } }
.map { flows -> combine(flows) { it.toList() } }
.flattenMerge()
It seems that the flattenMerge() is the key to this. If I use the default concurrency parameter (16), or a value larger than one (2 works) then I get updates from the info get all. But if the concurrency is set to 1, then it's effectively the same as flattenConcat - which doesn't work!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Yokich |
