I'm working on an Android app, and in my VM I have...
# coroutines
c
I'm working on an Android app, and in my VM I have an init {} block with 3 separate "inifinite" collect {} calls. viewModelScope.launch { launch { service.flow1().collect { } } launch { service.flow2(NEED an id FROM flow 1).collect { } } launch { service.flow3(NEED an id FROM flow 1).collect { } } } What would be the best way to do something like that?
e
is your intention something along these lines?
Copy code
service.flow1().mapLatest { id ->
    coroutineScope {
        service.flow2(id).launchIn(this)
        service.flow3(id).launchIn(this)
    }
}.buffer(0).launchIn(viewModelScope)
which will re-start
flow2
,
flow3
with each
id
from
flow1
. (or else what do you expect to happen before an
id
is available, or after a new value arrives?)
c
hm. its close. My "issue" is that flow1() will called a bunch, but the id I need will likely never change, but I need that id first so I can call flow2 and flow3, but flow1 still needs to do a bunch of work. I think a really simple (but inefficient solution to my problem would be this.
Copy code
viewModelScope.launch {
    val initialValue = service.flow1().first().someProperty
    launch { service.flow1().collect { //update UI with changes } }
    launch { service.flow2(initialValue).collect { //update UI with changes} }
    launch { service.flow3(initialValue).collect { //update UI with changes} }
}
So why I think
Copy code
service.flow1().mapLatest { id ->
    coroutineScope {
        service.flow2(id).launchIn(this)
        service.flow3(id).launchIn(this)
    }
}.buffer(0).launchIn(viewModelScope)
wouldn't work is because I don't know where I would do the //update UI with changes for flow1() since the result of Flow1 is a complex model, where I just need one property from that complex model to start flow2 and flow3.
f
you can convert your
flow
into a shared flow after you map it to the
id
, then use that shared flow to drive your
flow2
and
flow3
, something like this
Copy code
val idFlow = flow1.map { value ->
            // do whatever processing you need with value here
            value.id
        }.distinctUntilChanged()
            .shareIn(viewModelScope, SharingStarted.Eagerly)

        idFlow.flatMapLatest { id ->
            flow2(id)
        }.onEach { value -> 
            // handle value
        }.launchIn(viewModelScope)

        idFlow.flatMapLatest { id ->
            flow3(id)
        }.onEach { value ->
            // handle value
        }.launchIn(viewModelScope)
another option is to make your
flow
shared and then launch 3 collectors on that
Copy code
val sharedFlow = flow1
    .shareIn(viewModelScope, SharingStarted.Eagerly)

sharedFlow
.onEach { flow1Value ->
    // handle value from flow1
}.launchIn(viewModelScope)

sharedFlow
.map { value -> value.id}
.distcintUntilChanged()
.flatMapLatest { id ->
    flow2(id)
}.onEach { value ->
    // handle value
}.launchIn(viewModelScope)

sharedFlow
.map { value -> value.id}
.distcintUntilChanged()
.flatMapLatest { id ->
    flow3(id)
}.onEach { value ->
    // handle value
}.launchIn(viewModelScope)
1
c
oh boy. okay. lots of new apis there and kinda going over my head, but im going to try to learn some more of these starting tomorrow. thanks all