https://kotlinlang.org logo
l

Landry Norris

07/26/2021, 9:45 PM
I'm currently experimenting with using a SharedFlow in my Repository object, and using Compose's collectAsState() function. I noticed that emitting values doesn't update my composable. I ran a debugger with a breakpoint both on the emit line and on the internals of collectAsState. I can see that
Copy code
collect { value = it }
inside of collectAsState() does get called, and 'it' has the correct value, but the UI does not change. The UI did properly respond when I used LiveData and observeAsState(), but I am wanting to switch to Flows.
z

Zach Klippenstein (he/him) [MOD]

07/26/2021, 9:50 PM
Can you post the code for the composalbe that calls
collectAsState
?
l

Landry Norris

07/26/2021, 9:51 PM
Copy code
val itemsState = viewModel.filteredItems.collectAsState(initial = ArrayList())
LazyColumn(modifier = Modifier.fillMaxSize()) {
    itemsIndexed(itemsState.value) { _, item ->
        Card {
            TodoRow(
                item = item,
                onStarClicked = viewModel::onStarClicked,
                onTextChanged = viewModel::setNote,
                onDoneClicked = viewModel::onDoneClicked,
                onTrashClicked = viewModel::onTrashClicked
            )
        }
    }
}
z

Zach Klippenstein (he/him) [MOD]

07/26/2021, 9:52 PM
How is that
filteredItems
property defined?
Unrelated, but you probably want to define a constant for that initial value so it’s not allocating a new
ArrayList
on every recomposition, just to immediately throw it away
l

Landry Norris

07/26/2021, 9:52 PM
Copy code
val filteredItems = MutableSharedFlow<MutableList<ToDoItem>>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
When a change occurs, I call filteredItems.tryEmit(ArrayList(cache)) //We need to emit a "new" ArrayList to force the UI to update
z

Zach Klippenstein (he/him) [MOD]

07/26/2021, 9:53 PM
General note, it’s more idiomatic in kotlin to not use
ArrayList
directly but instead use
List
as the type and
listOf()
to create them
Wait, why does your
MutableSharedFlow
hold a
MutableList
? Are you mutating it ever?
l

Landry Norris

07/26/2021, 9:58 PM
It holds an ArrayList. Calling emit has an effect, since the breakpoint I set inside of collectAsState() (SnapshotState.kt line 799) gets hit, and I can see the new value in the debugger, but when I press play on the debugger, I don't see the UI properly update.
You are right that I never mutate the list itself, so I could make it just a List. I'll add that to the things to refactor when I get it working, but shouldn't have an effect on whether the SharedFlow calls its observers.
z

Zach Klippenstein (he/him) [MOD]

07/26/2021, 11:08 PM
yea
listOf
uses an ArrayList under the hood i believe, so it should still work
i’m not sure what’s going on here, from what you’ve said it sounds like you’ve done everything right
which version of compose are you using?
l

Landry Norris

07/26/2021, 11:45 PM
RC02
I got my debugger to the section where it checks that the new value is not equal to the old, and saw that the references are different, which is expected.
y

yousefa2

07/27/2021, 5:47 AM
Make sure that you define a suitable key for each item in
LazyColumn
.
LazyColumn
takes a lambda that allows you to compute a key per item. If you don't supply this lambda it uses the item index as key.
☝🏻 1
l

Landry Norris

07/27/2021, 2:17 PM
I've just been using the index before, and it worked with LiveData lists. I can look into supplying a key.
Added key based on item hashcode and item id separately. It had no effect.
6 Views