I want to concatenate the results of two SQL queries I implemented using the Room library. I will put an example to present it more clearly:
In my DAO file:
@Query(SELECT plantId FROM PlantView WHERE language = :language
fun getPlantByLang(language: String): Flow<List<Plant>>
@Query(SELECT plantId FROM PlantView WHERE location = :location
fun getPlantByLoc(location: String): Flow<List<Plant>>
Now, in my viewController, I want that getPlants returns a Flow of Plant that is a concatenation of the two flows above [flow1, flow2]. One after the other. So then I can collect both flows into one in the UI state (Screen file):
val plantList by viewModel.getPlants().collectAsState(emptyList())
The reason why I want these two flows and not a single query is because actually each one will generate slightly different Plant instances, so the output of each flow will be drawn differently in the UI, being both inside the plantList.
I tried to concatenate the two flows using onCompletion as in this SO answer:
fun getPlants (lang: String, loc: String) = getPlantByLang(lang).onCompletion{emitAll(getPlantByLoc(loc)}
But this returns the results of the first flow (byLang) only. I guess this is because of this DAO query being a hot flow, which never completes.
I tried also using flattenConcat with same outcome:
fun getPlants (lang: String, loc: String) = flowOf( getPlantByLang(lang), getPlantByLoc(loc) ).flattenConcat()
Finally, I tried using merge
hoping to at least get both flows in one besides they wouldn't be one after the other:
fun getPlants (lang: String, loc: String) = merge( getPlantByLang(lang), getPlantByLoc(loc) )
And the outcome is a infinite loop of getting first one flow, UI refreshes, then the other, UI refreshes, and so on.
Any ideas? I supposed it shouldn't be that difficult to concatenate the output of two flows into one flow.
I think what you want to achieve is not to concatenate the Flows, you want to concatenate the Lists (i.e., the content of the flows).
This can be done using combine
:
fun getPlants(lang: String, loc: String): Flow<List<Plant>> =
combine(
getPlantByLang(lang),
getPlantByLoc(loc),
) { plantsByLanguage, plantsByLocation ->
plantsByLanguage + plantsByLocation
}
Pass all the flows you want to combine as parameters. You can then use the lambda to access their content. plantsByLanguage
and plantsByLocation
are both of type List<Plant>
because that's the type of their respective flows. The return value of the lambda determines the content of the combined flow. Since you want the lists to be concatenated, I used plantsByLanguage + plantsByLocation
which returns a new List<Plant>
which contains the entries of plantsByLanguage and then the entries of plantsByLocation.