https://kotlinlang.org logo
#compose-android
Title
# compose-android
d

dazza5000

02/28/2024, 10:06 PM
I can post a complete sample project, but I am having some serious performance issues with animateFloatAsValue and LaunchedEffect with the float value as a key. Below is a concise example
Copy code
val angle: Float by animateFloatAsState(
        targetValue = if (animationRunning)
            finalAngle
        else 0f,
        animationSpec = tween(durationMillis = SPIN_DURATION.toInt()),
        label = "AnimateWheel",
    )

    LaunchedEffect(angle) {
        
    }
Just setting an empty LaunchedEffect results in like 1000x slower animation
noLaunchedEffect.webm
EmptyLaunchedEffect.webm
In the view system we had ValueAnimator.addUpdateListener which didn't appear to have any noticeable performance impact
s

Stylianos Gakis

02/28/2024, 10:11 PM
Why are you restarting an entire LaunchedEffect (which has to cancel the previous work and then start a new coroutine eachtime) on basically every single frame? What are you trying to do inside that LaunchedEffect that needs to be re-run so often?
☝🏻 1
d

dazza5000

02/28/2024, 10:18 PM
We vibrate the wheel to simulate a real spin wheel at particular rotations
Copy code
if (newAngle > nextVibrationAngle) {
                    nextVibrationAngle += sliceAngle
                    future?.cancel(true)
                    future = executor.submit {
                        context?.let { VibrationCompat.vibrate(it, EffectType.WHEEL_TICK) }
                    }
                }
Here is the compose variant
Copy code
LaunchedEffect(angle) {
            if (angle > nextVibrationAngle) {
                nextVibrationAngle += sliceAngle
                job?.cancel()
                job = launch {
                    context.let { VibrationCompat.vibrate(it, EffectType.WHEEL_TICK) }
                }

                Log.d("WheelViewCompose", "Vibrating! $nextVibrationAngle")
            }
    }
this creates a truly immersive experience 😜
Will probably just switch to using a timing approach instead of observing the angle
Still concerning that an empty LaunchedEffect has such a significant performance impact
b

Ben Trengrove [G]

02/28/2024, 10:46 PM
Ideally our APIs wouldn't lead you down this path, but that is a misuse of the LaunchedEffect API which is what Stylianos is saying. The way you have written it you are going to be creating and launching a coroutine on every frame because you are using
angle
as a key
👆 2
Have a look at this example in the animation docs which is close to what you want https://developer.android.com/jetpack/compose/animation/value-based#targetbasedanimation
You probably want
animationRunning
as your key
Something like this will observe the value of angle and not relaunch on every frame
Copy code
LaunchedEffect(animationRunning) {
   if (animationRunning) {
      snapshotFlow { angle }.collect { angle ->
         // use angle
      }
   }
}
d

dazza5000

02/28/2024, 11:44 PM
will give that a try - thank you ben
that worked - thank you Ben
2 Views