Thread
#compose
    Landry Norris

    Landry Norris

    1 year ago
    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
    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.
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    Can you post the code for the composalbe that calls
    collectAsState
    ?
    Landry Norris

    Landry Norris

    1 year ago
    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
                )
            }
        }
    }
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    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
    Landry Norris

    Landry Norris

    1 year ago
    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
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    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?
    Landry Norris

    Landry Norris

    1 year ago
    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.
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    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?
    Landry Norris

    Landry Norris

    1 year ago
    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.
    yousefa2

    yousefa2

    1 year ago
    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.
    Landry Norris

    Landry Norris

    1 year ago
    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.