How to get updated results in StateFlow depending on parameter (sorting a list) with Jetpack Compose

Viewed 60

I made a state with StateFlow with 2 lists. This is working good. I want to sort these lists according to a parameter that user will decide how to sort. This is my code in ViewModel:

@HiltViewModel
class SubscriptionsViewModel @Inject constructor(
    subscriptionsRepository: SubscriptionsRepository
) : ViewModel() {    
private val _sortState = MutableStateFlow(
    SortSubsType.ByDate
)
val sortState: StateFlow<SortSubsType> = _sortState.asStateFlow()

val uiState: StateFlow<SubscriptionsUiState> = combine(
    subscriptionsRepository.getActiveSubscriptionsStream(_sortState.value),
    subscriptionsRepository.getArchivedSubscriptionsStream(_sortState.value)
) { activeSubscriptions, archiveSubscriptions ->

    SubscriptionsUiState.Subscriptions(
        activeSubscriptions = activeSubscriptions,
        archiveSubscriptions = archiveSubscriptions,
    )
}
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000),
        initialValue = SubscriptionsUiState.Loading
    )

fun sortSubscriptions(sortType: SortSubsType) {
    _sortState.value = sortType
}
}
sealed interface SubscriptionsUiState {
    object Loading : SubscriptionsUiState

    data class Subscriptions(
        val activeSubscriptions: List<Subscription>,
        val archiveSubscriptions: List<Subscription>,
    ) : SubscriptionsUiState

    object Empty : SubscriptionsUiState
}

sortSubscriptions - is the function called from @Composable screen. Like this:

  fun sortSubscriptions() {
        viewModel.sortSubscriptions(sortType = selectedSortType.asSortSubsType())
        isSortDialogVisible = false
    }

Without the sort function, everything works. My question is how to fix this code so that the state changes when the sortState is changed. This is my first try working with StateFlow.

1 Answers

The problem is that when you create your uiState flow with combine, you just use the current value of sortState and never react to its changes.

You need something like this:

val uiState = sortState.flatMapLatest { sortValue ->
    combine(
        getActiveSubscriptionsStream(sortValue),
        getArchivedSubscriptionsStream(sortValue)
    ) { ... }
}.stateIn(...)
Related