paparazzi
paparazzi copied to clipboard
Compose async effects are halted
Description
Compose async effects like LaunchedEffect, don't appear to run naturally.
Steps to Reproduce
@Test
fun delay() {
val start = System.currentTimeMillis()
println(0)
paparazzi.gif(start = 2500L, end = 2500L, fps = 1) {
var state by remember { mutableStateOf(0) }
LaunchedEffect(Unit) {
println("${System.currentTimeMillis() - start} Launched Effect")
state++
while (true) {
delay(10)
state++
println("${System.currentTimeMillis() - start} Delayed")
}
}
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Center) {
Text("Value: $state")
}
}
println("" + (System.currentTimeMillis() - start) + " end")
}
Text output is like
0
Jul. 23, 2022 4:19:10 PM app.cash.paparazzi.internal.PaparazziLogger logAndroidFramework
INFO: Settings [3]: Can't get key animator_duration_scale from content://settings/global
470 Launched Effect
485 Delayed
812 end
Screen Output is "Value: 2"
Expected behavior
Output is some high number like 51?
Additional information:
- Paparazzi Version: 1.0
Switching onto Dispatchers.Default fixes it, so possibly it is contention on the main thread?
As another example
@Test
fun mediaPlayerScreen() {
paparazzi.gif(start = 500L, end = 5000L, fps = 1) {
val state = rememberScalingLazyListState()
ScalingLazyColumn(
horizontalAlignment = CenterHorizontally,
state = state
) {
items(10) {
Text(text = "Item $it")
}
}
}
}
This video https://user-images.githubusercontent.com/231923/180612278-93e83b60-2a49-4b37-8d1e-94620cc16c7f.mov
Shows the delay in rendering.
From reading the code, my impression is that there is some missing logic with how Paparazzi simulates time. But I'm out of my depth.
private fun withTime(
timeNanos: Long,
block: () -> Unit
) {
val frameNanos = TIME_OFFSET_NANOS + timeNanos
Does the existing notion of frame time integrate with Compose currently?
Virtual time control would be very useful. There are many useful applications of this. For example, verifying appearance at the endpoint of an animation. In fact, any time you'd use virtual time in a semantic UI test, is also applicable to a screenshot test.
I'm really stuck on using Compose for anything with async effects, happy to dig into it, but would love some guidance. Currently I can use paparazzi for about 40% of my screens, but anything with ScalingLazyColumn on wear doesn't work because it is async.
Switching onto Dispatchers.Default fixes it, so possibly it is contention on the main thread?
How did you switch onto Dispatcher.Default? Could that be workaround?
coroutineScope(Dispatchers.Default)
My read is that LaunchedEffect runs on main thread, after composition. So things work until it suspends.
Running on the background dispatchers only sort of works. It runs in the background, untied from frames. So two identical tests will progress to different points, the second getting further because it's warmed up I guess.
It's not a reliable solution
Fixed in #739