I'm creating a flow out of snapshot state. ```val ...
# compose
c
I'm creating a flow out of snapshot state.
Copy code
val listFlow = snapshotFlow { appState.myList }
viewModelScope.launch {
  listFlow.collectLatest {
Log...
but even when I clear the list and addAll to it, my flow doesn't get fired again (I don't see my log). Am I misunderstanding snapshotFlow, or should this work?
s
What's the type of
myList
?
c
mutableStateListOf<String>
s
Right, when we use
stateFlow
, we have to use it with
T
where
T
has to be backed by a
MutableState
so that its observers get notified (this case the snapshotFlow has subscribed to see its changes and is observing that value), instead of passing a
State<T>
in the
stateFlow
lambda. That’s my understanding of it. So this does not work for `snapshotFlow`:
Copy code
val state: State<String> = produceState("") {
  while(isActive) {
    value = "one"
    delay(1.seconds)
    value = "two"
    delay(1.seconds)
  }
}
LaunchedEffect(Unit) {
  snapshotFlow { state }.collectLatest {
    println("state:$state")
  }
}
But this does:
Copy code
val state: String by produceState("") {
  while(isActive) {
    value = "one"
    delay(1.seconds)
    value = "two"
    delay(1.seconds)
  }
}
LaunchedEffect(Unit) {
  snapshotFlow { state }.collectLatest {
    println("state:$state")
  }
}
In your case you got the type
SnapshotStateList<T>
but you want to use
snapshotFlow
on your
<T>
instead. This does not work
Copy code
val state: SnapshotStateList<String> = mutableStateListOf("One", "Two")
LaunchedEffect(Unit) {
  while (isActive) {
    delay(1.seconds)
    state.add("one")
    delay(1.seconds)
    state.add("two")
    delay(1.seconds)
    state.clear()
  }
}
LaunchedEffect(Unit) {
  snapshotFlow { state }.collectLatest {
    println("state:$state")
  }
}
But this does
Copy code
This does not work
val state: SnapshotStateList<String> = mutableStateListOf("One", "Two")
LaunchedEffect(Unit) {
  while (isActive) {
    delay(1.seconds)
    state.add("one")
    delay(1.seconds)
    state.add("two")
    delay(1.seconds)
    state.clear()
  }
}
LaunchedEffect(Unit) {
  snapshotFlow { state.toList() }.collectLatest {
    println("state:$state")
  }
}
a
See this thread. Read the values of the list in the lambda of
snapshotFlow
.
s
Can’t believe I didn’t think of just
.toList()
😅 So for your original post do instead
Copy code
val listFlow = snapshotFlow { appState.myList.toList() }
viewModelScope.launch {
  listFlow.collectLatest {
Log...
c
No way. All I had to do was
.toList()
Oh man. so much time wasted debugging this yesterday. lmaooo
s
I was looking into the
SnapshotStateList
class to see if something that can extract the values exists and there wasn’t anything in there aside from
get(index)
. But my brain completely forgot to make the connection that
SnapshotStateList
is in fact a
MutableList
which is a
List
which is a
Collection
which is a
Iterable
which you can call the
public fun <T> Iterable<T>.toList(): List<T>
function on it. Felt like I was back in the CS class on this one, learning Java inheritance and interfaces 😅
c
I don't really know if this is what happens but I would think .toList() is "wasteful" because... It's already a list so why waste the time converting it to a list again?
s
I don’t think this converts anything in a wasteful manner. It simply gets the underlying list that is saved inside the
SnapshotStateList
and since you’re doing it inside the
snapshowFlow
it also subscribes to any changes it may get. Could be wrong, but I wouldn’t even think about it.
c
Memory-wise it is wastfull.
toList()
will create a new list with the same content.
s
Yeah but what other option does one have in this case?
c
I’d probably change my architechture. Not sure about your use case. But sounds kind of hacky what you are doing. Why do you meet the state then in the first place if you use it as a flow. There is
channelFlow
builder that you can use to emit your “state”.
z
You can use
snapshotFlow
as the full restart scope. Eg you could do something like this:
Copy code
viewModelScope.launch {
  snapshotFlow {
    appState.myList.forEach // or w/e
    // put all your list processing here
    // return type doesn't matter
  }.collect()
}
c
Interesting. I just want to know when the list is cleared or items are added. So maybe a for each will get the job done.
164 Views