3

In my project, I have two fragments.

One is a normal fragment, and another is a bottomSheetDialogFragment.

In my normal fragment, I have a lazyColumn.

I would like to do some settings in the bottomSheetDialogFragment and create a new Hiit object and put it into my hiitItems list in my viewmodel.

The problem is that since my normal fragment is partially covered by the bottomSheetDialogFragment, jetpack compose won't re-compose when my list changes.

So I decided to turn to stateFlow given that it is always firing, and I assume this might cause recomposition. But unfortunately, it did not.

Below are my codes:

// in my viewmodel
// using stateflow to hold the list of hiitItems 
    private var _hiitItems = MutableStateFlow(mutableListOf(HiitItem()))
    val hiitItems = _hiitItems

In my normal fragment, I'm using composeView to take advantage of jetpack compose:

 setContent {

// get hiitItems
val hiitItems by vm.hiitItems.collectAsState()
...

 // lazyColumn
LazyColumn(modifier = Modifier.fillMaxSize()) {
    items(hiitItems) // I'm assuming auto refreshing the list here
    {
     ItemCard(item = it) // ItemCard is just an ordinary composable
    }
 }
}

In my bottomSheetDialogFragment, I have a button, whose function is to add the newly created hiitItem into my hiitItems list, and cause recomposition:

 hiitItems.add(newItem)

Any idea why the change in my hiitItems list is not causing recomposition after I dismiss my bottomSheetDialogFragment?

Fever
  • 157
  • 2
  • 9
  • I have been stuck for two days for this weird behavior. My two fragments are using the same viewmodel. I also tried the mutableStateOf( listOf() ) approach. Let's say if I put two lazyColunns respectively on each fragment, then the bottom SheetFragment will correctly display my lazyColumn after auto-recomposition, but my partially-covered fragment won't. And it won't show anything when it is no longer covered either, even when these two fragments are using the same reference to a list in my viewmodel. – Fever Dec 29 '21 at 15:26

2 Answers2

7

Your mutableStateFlow is not firing because you are mutating the list. Instead of adding an item to the list (mutating it) make a new list with the new item and update your flow with it.

private var _hiitItems = MutableStateFlow(emptyList<HittItem>())

and later

_hiitItems.value = _hiitItems.value + newItem
Francesc
  • 25,014
  • 10
  • 66
  • 84
1

Solved! Turns out the issue had nothing to do with my MutableStateFlow.

It was viewModel scope that was causing the failure.

Specifically speaking, my normal fragment and bottomSheetDialogFragment each has a distinct viewModel scope. Therefore, although they did have references to the same viewmodel, the normal fragment failed to observe the changes caused by the bottomSheetDialogFragment, which is why the recomposition never fired.

For those who might be suffering from a similar issue as I did, you can check this answer and this article for elabaration!

The takeaway is to make sure that you always acquire the shared viewModel via

val sharedViewModel = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)

in different fragments where you want to share the same viewmodel scope.

Fever
  • 157
  • 2
  • 9