I have an activityUiState (of type ActivityUiState) object which has a list of sub-activities (of type ActivityUiState as well) and a list of voice notes. I'm trying to populate the activityUiState with the list of sub-activities and voice notes using flows. Each of the sub-activities might have its own voice notes saved in the database that I would like to include in the sub-activity objects when I'm creating the sub-activity list. The code so far adds sub-activities and voice notes to the activityUiState successfully. However, when I try to add the voice notes of each of the sub-activities, the whole activityUiState object is not updated with any of the data. What am I doing wrong here?
var subActivitiesUiState = emptyList<ActivityUiState>()
activitiesRepository.getSubActivitiesPerMainActivity(id).collect { subActivities ->
for (subActivity in subActivities) {
var voiceNotesUiState = emptyList<VoiceNoteUiState>()
// This code block results in an empty activityUiState being returned
/*
voiceNotesRepository.getAllVoiceNotesPerActivity(subActivity.id).collect { voiceNotes ->
for (voiceNote in voiceNotes) {
// Append the mapped voice note to the voice notes list
voiceNotesUiState = voiceNotesUiState + VoiceNoteUiState(
id = voiceNote.id,
uri = voiceNote.uri,
duration = voiceNote.duration,
timestamp = voiceNote.timestamp,
activityId = voiceNote.activityId
)
}
subActivitiesUiState = subActivitiesUiState + ActivityUiState(
id = subActivity.id,
title = subActivity.title,
note = subActivity.note,
startTime = subActivity.startTime,
endTime = subActivity.endTime,
voiceNotesUiState = voiceNotesUiState,
mainActivityId = subActivity.mainActivityId
)
}
*/
subActivitiesUiState = subActivitiesUiState + ActivityUiState(
id = subActivity.id,
title = subActivity.title,
note = subActivity.note,
startTime = subActivity.startTime,
endTime = subActivity.endTime,
voiceNotesUiState = voiceNotesUiState,//TODO: Add the voice notes of the sub-activity
mainActivityId = subActivity.mainActivityId
)
}
activityUiState.update {
ActivityUiState(
id = activity.id,
title = activity.title,
note = activity.note,
startTime = activity.startTime,
endTime = activity.endTime,
subActivitiesUiState = subActivitiesUiState
)
}
var voiceNotesUiState = emptyList<VoiceNoteUiState>()
voiceNotesRepository.getAllVoiceNotesPerActivity(id).collect { voiceNotes ->
for (voiceNote in voiceNotes) {
// Append the mapped voice note to the voice notes list
voiceNotesUiState = voiceNotesUiState + VoiceNoteUiState(
id = voiceNote.id,
uri = voiceNote.uri,
duration = voiceNote.duration,
timestamp = voiceNote.timestamp,
activityId = voiceNote.activityId
)
}
activityUiState.update { it ->
it.copy(
voiceNotesUiState = voiceNotesUiState
)
}
}
}
UPDATE 25.11.2025
Based on tyg's suggestion I changed my code to the following:
val selectedActivityId = MutableStateFlow(savedStateHandle.get(ACTIVITY_ID_SAVED_STATE_KEY))
val activityUiState = MutableStateFlow(ActivityUiState())
selectedActivityId.flatMapLatest { activityId ->
@OptIn(ExperimentalCoroutinesApi::class)
val activityState = selectedActivityId.flatMapLatest { activityId ->
if (activityId == null) return@flatMapLatest flowOf(ActivityUiState())
val flowOfActivity = activitiesRepository.getActivityStream(activityId)
val flowOfSubActivities = activitiesRepository.getSubActivitiesPerMainActivity(activityId).flatMapLatest { subActivities ->
val subActivitiesUiStates = subActivities.map { subActivity ->
voiceNotesRepository.getAllVoiceNotesPerActivity(subActivity.id).map { voiceNotes ->
ActivityUiState(
date = subActivity.date,
id = subActivity.id,
title = subActivity.title,
note = subActivity.note,
startTime = subActivity.startTime,
endTime = subActivity.endTime,
voiceNotesUiState = voiceNotes.map { voiceNote ->
VoiceNoteUiState(
id = voiceNote.id,
uri = voiceNote.uri,
duration = voiceNote.duration,
timestamp = voiceNote.timestamp,
activityId = subActivity.id
)
},
mainActivityId = subActivity.mainActivityId
)
}
}
combine(subActivitiesUiStates) { it -> it.toList() }
}
combine(
flowOfActivity,
flowOfSubActivities,
voiceNotesRepository.getAllVoiceNotesPerActivity(activityId)
) { activity, subActivitiesUiStates, voiceNotes ->
activity?.let {
activityUiState.update {
it.copy(
date = activity.date,
id = activity.id,
title = activity.title,
note = activity.note,
startTime = activity.startTime,
endTime = activity.endTime,
voiceNotesUiState = voiceNotes.map{ voiceNote ->
VoiceNoteUiState(
id = voiceNote.id,
uri = voiceNote.uri,
duration = voiceNote.duration,
timestamp = voiceNote.timestamp,
activityId = activity.id
)
},
subActivitiesUiState = subActivitiesUiStates
)
}
ActivityUiState(
date = activity.date,
id = activity.id,
title = activity.title,
note = activity.note,
startTime = activity.startTime,
endTime = activity.endTime,
voiceNotesUiState = voiceNotes.map{ voiceNote ->
VoiceNoteUiState(
id = voiceNote.id,
uri = voiceNote.uri,
duration = voiceNote.duration,
timestamp = voiceNote.timestamp,
activityId = activity.id
)
},
subActivitiesUiState = subActivitiesUiStates
)
} ?:run {
activityUiState.update {
ActivityUiState()
}
ActivityUiState()
}
}
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5000L),
initialValue = ActivityUiState()
)
fun selectActivity(id: UUID?) {
selectedActivityId.value = id
}
I need the activityUiState to be of type MutableState, so I'm using the activityState as a Flow. The voice notes of subsequent sub-activities are loaded now, thank you
Could you also help me with this little problem: the activityState and activityUiState are not always updated when the selectedActivityId's value changes.