gitai
06/26/2021, 10:10 PMSnapshot.takeMutableSnapshot()
, when inside a readObserver
callback, how do you subscribe a composable to reads of the supplied state instance?Zach Klippenstein (he/him) [MOD]
06/27/2021, 2:40 AMgitai
06/27/2021, 5:53 AMreadObserver
states: “Composition, layout and draw use readObserver to implicitly subscribe to changes to state objects to know when to update”. This suggests to me that readObserver
serves as a place where you subscribe a composable to the State
object provided by the callback parameter… Why would you otherwise care about State
read? I mean you can’t know (read) State.value
inside the callback, that will lead to infinite recursion so what else can you do with the State
instance ?Zach Klippenstein (he/him) [MOD]
06/27/2021, 5:04 PMI’m trying to figure out how to make use of this ApiWhat are you trying to do with the API though? These APIs are very low-level you shouldn’t need to use them unless you’re building your own Compose-like framework.
I mean you can’t know (read)What callback? Again, not sure what you’re trying to do. Are you trying to build some UI? Build a framework?inside the callbackState.value
gitai
06/27/2021, 5:27 PMWhat are you trying to do with the API though? These APIs are very low-level you shouldn’t need to use them unless you’re building your own Compose-like framework.I'm not trying to build anything at this point. I'm trying to understand what state management facilities are at my disposal. BTW. I Love low-level 🙂
What callback?The
readObserver
callback.gitai
06/27/2021, 6:00 PMval state = mutableStateOf(0)
val readObserver: (Any) -> Unit = { observedState ->
// So I know some state was read, so what ?
if (observedState == state) {
// Ok, I can tell it's some specific state...
// But I can't tell what value it stores... Uncomment to see why.
// println("state.value: ${state.value}")
println("state read")
// So what do you do with an 'observedState' ?
// The docs suggest you can register it with a composable, but how ??
}
}
val snapshot = Snapshot.takeMutableSnapshot(readObserver)
snapshot.enter {
println("${state.value}")
}
snapshot.dispose()
Zach Klippenstein (he/him) [MOD]
06/27/2021, 6:59 PMZach Klippenstein (he/him) [MOD]
06/27/2021, 7:03 PMZach Klippenstein (he/him) [MOD]
06/27/2021, 7:06 PMgitai
06/27/2021, 7:21 PMSo any time a composable is executed, it’s actually executed inside a read observer that is registered by the compose runtime.What do you mean by "read observer" ? The snapshot.enter scope is where code executes and the scope observes both reads and writes... the read/write observers above are notification callbacks functions observed code doesn't run in these callbacks.
Zach Klippenstein (he/him) [MOD]
06/27/2021, 7:54 PMsnapshotFlow
- take a look at that. The callbacks merely notify you that the code running in the context of the snapshot read or wrote some state value.Zach Klippenstein (he/him) [MOD]
06/27/2021, 8:03 PM@Composable fun Display(value: State<*>) {
Text(value.value.toString())
}
Then when the runtime actually runs that function, it does something like this pseudo code:
val readStates = mutableSetOf<*>()
observeReads(
onRead = { readStates += it },
codeToObserve = { Display(value) }
)
addGlobalWriteObserver(
onWrite = { writtenState ->
if (writtenState in readStates) {
scheduleRecomposition()
}
}
)
Those aren’t the actual APIs or code but conceptually that’s basically how the observe logic works.
observeReads
executes codeToObserve
immediately and invokes onRead
any time codeToObserve
reads a state value. Then, any time any state value is written anywhere in the process, we check if it was one of the values read by codeToObserve
and, if it was, schedule a recomposition to eventually run and process the new state value.gitai
06/27/2021, 9:55 PMZach Klippenstein (he/him) [MOD]
06/28/2021, 1:03 AMZach Klippenstein (he/him) [MOD]
06/28/2021, 1:04 AM