Home > Software engineering >  is it possible collect multiple flows in one
is it possible collect multiple flows in one

Time:11-27

what I want to do is get network data by firebase AddSnapshotListener, store it in room database and get data from room database

so what I done is down here...

// in dataSource
fun getNetworkData(id : String) = callbackFlow<Data> {
    ....
    streamingApi.get{
        trySend(it)
    }
    ...
}


//in repository
fun insertData(id : String) = getNetworkData(id).map{
    roomDao.insert(it)
}

fun getRoomData() = roomDao.get()



// viewmodel
viewmodelScope.launch{
    repository.insertData(id).collect()
    repository.getRoomData().onEach{
        updateUi()
        ...
    }
}

but is it possible collect at once like this?

fun insertAndGet() = flow{
    insertData().collect()
    getRoomData().collect()
}

and is it right way collect flow in repository?

CodePudding user response:

You can use merge to combine flows which takes vararg flows as argument.

fun insertAndGet() = merge(insertData(),getRoomdata())

Here if your insertData and getRoomData has flow of same type ,

insertAndGet() will also be in same type. If they are different, both will be combined but result from combined flow will be of type Any.

Usage:

fun someFun(){
  viewModelScope.launch{
   insertAndGet().collect{
  // You consume the emitted result by using it. And update UI based on the data.
   }
  }
}

Please refer here.

CodePudding user response:

insertData() is kind of weird because it returns a Flow of Units. I think it would make more sense to use onEach instead of map so it at least returns a Flow that you could theoretically do something with other than just pass through data and then drop it.

But regardless, the data will be passed out of the getRoomData() flow so it doesn’t really matter. If you combine the two, you can just drop the redundant data from the insertData() flow.

In my opinion, these separate actions should not be combined into a single flow because they have different responsibilities, but I suppose you could do the following. Since the two flows run indefinitely, they must be collected in parallel. This flow just collects the insert flow so it will do its action, but doesn’t pass along the values. It is done in a parallel child coroutine. The Room flow’s data is simply passed out.

fun insertAndGet() = flow {
    coroutineScope {
        async { insertData().collect() }
        emitAll(getRoomData())
    }
}
  • Related