paparazzi icon indicating copy to clipboard operation
paparazzi copied to clipboard

Compose async effects are halted

Open yschimke opened this issue 2 years ago • 5 comments

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

yschimke avatar Jul 23 '22 15:07 yschimke

Switching onto Dispatchers.Default fixes it, so possibly it is contention on the main thread?

yschimke avatar Jul 23 '22 15:07 yschimke

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.

yschimke avatar Jul 23 '22 15:07 yschimke

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?

yschimke avatar Jul 24 '22 10:07 yschimke

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.

BenTilbrook avatar Aug 23 '22 05:08 BenTilbrook

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.

yschimke avatar Aug 28 '22 09:08 yschimke

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?

magdamagda avatar Dec 10 '22 21:12 magdamagda

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

yschimke avatar Dec 11 '22 10:12 yschimke

Fixed in #739

jrodbx avatar Mar 24 '23 01:03 jrodbx