2

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 onEach for 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"?

Yokich
  • 1,247
  • 1
  • 17
  • 31

1 Answers1

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!

Yokich
  • 1,247
  • 1
  • 17
  • 31