3
votes

I'm new to using flow and coroutines and I would like you to help me with the following problem:

I have the useCases.getScheduleList() and useCases.getScheduleDetails() methods that return a Flow. And I need to call useCases.getScheduleList() to get the schedule list and then call useCases.getScheduleDetails() for each item in the schedule list. Following is my attempt:

    viewModelScope.launch {
        useCases.getScheduleList().collect {
            val scheduleList = it
            val schedulesWithDetails = arrayListOf<ScheduleWithDetails>()

            for (schedule in scheduleList) {
                launch {
                    useCases.getScheduleDetails(schedule.code)
                        .collect { detail ->
                            schedulesWithDetails.add(
                                newScheduleWithDetail(
                                    schedule,
                                    detail.body
                                )
                            )
                        }
                }
            }

            // updateUI is called before collect add items to schedulesWithDetails
            updateUI(schedulesWithDetails)
        }
    }
}

In the code above I can collect the listing and also collect the detail of each item in the listing and add the results to my schedulesWithDetails but I cannot use schedulesWithDetails with the data already added because the updateUI() method does not wait for the collect process to finish in then be executed.

Can anyone help me with ideas/suggestions for this problem?

1
aren't you suppose to handle the getScheduleDetails inside the ViewModel ? - Ticherhaz FreePalestine
Yes, and I am doing this in the viewModel and I am also using viewModelScope.launch - Rafael J Silva
It's a huge red flag that you have a function called updateUi in your ViewModel. Referencing any UI from a ViewModel causes memory leaks. You should expose an appropriate flow for your Fragment/Activity to collect on its own. - Tenfour04
Hello, thanks for your observation. But the updateUI method was just an example that I put to represent that someone will use the result of schedulesWithDetails. I actually update the view through livedata. - Rafael J Silva

1 Answers

3
votes

Try this out:

viewModelScope.launch {
    useCases.getScheduleList().map { scheduleList ->
        scheduleList.map { async { useCases.getScheduleDetails(it).first() } }.awaitAll()
    }.collect { schedulesWithDetails ->
        updateUi(schedulesWithDetails)
    }
}