Sri
12/22/2022, 4:59 AMMutableState
using snapshotFlow
and turbine.
A simplified version of the class looks like like this
class Foo(scope: CoroutineScope) {
val bar = mutableStateOf(1)
init {
scope.launch {
delay(1000)
bar.value = 2
}
}
}
The test method looks like this
@Test
fun test() {
val testScope = TestScope(StandardTestDispatcher())
testScope.runTest {
val foo = Foo(testScope)
snapshotFlow { foo.bar.value }
.test {
val item1 = awaitItem()
println(item1)
val item2 = awaitItem()
println(item2)
}
}
}
My expectation was that it would print 1
followed by 2
. This test always fails with timeout after printing 1
. When using snapshotFlow
outside of the test environment it works as expected. I am unclear on what I am doing wrong and was looking for some guidance. Thank you.jw
12/22/2022, 5:06 AMvar scheduled = false
Snapshot.registerGlobalWriteObserver {
if (!scheduled) {
scheduled = true
scope.launch {
scheduled = false
Snapshot.sendApplyNotifications()
}
}
}
jw
12/22/2022, 5:07 AMregisterGlobalWriteObserver
return a handle that you could call to dispose of your observer. you could create a JUnit rule that added this for all tests in that file, for exampleSri
12/22/2022, 5:12 AMjw
12/22/2022, 5:13 AMSri
12/22/2022, 5:13 AMjw
12/22/2022, 5:17 AMZach Klippenstein (he/him) [MOD]
12/22/2022, 5:21 AMjw
12/22/2022, 5:23 AMjw
12/22/2022, 5:23 AMZach Klippenstein (he/him) [MOD]
12/22/2022, 5:28 AMZach Klippenstein (he/him) [MOD]
12/22/2022, 5:33 AMsnapshotFlow
uses to trigger the flow emission. When the latter happens, no apply notification is sent until the next snapshot is applied (might be never) so Jake’s code manually fires it.
Compose UI, Jake’s Mosaic, and Molecule all have code that basically looks exactly like that. The reason these are separate steps is because many different states might get written to at different times, and the runtime might not want to process those updates until some point in the future (eg the next frame).Sri
12/22/2022, 7:09 AMAlex Vanyo
01/04/2023, 6:02 PMsendApplyNotifications
is being done by Compose UI:
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]androidx/compose/ui/platform/GlobalSnapshotManager.android.kt
One notable edge-case of this in production code if you’re using interop is that snapshotFlow
won’t emit updates unless a piece of Compose UI has been displayed at least once: https://issuetracker.google.com/issues/228228179