Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

withTiming / withRepeat slowdown on Android #6531

Open
deanhet opened this issue Sep 20, 2024 · 4 comments
Open

withTiming / withRepeat slowdown on Android #6531

deanhet opened this issue Sep 20, 2024 · 4 comments
Labels
Missing repro This issue need minimum repro scenario Platform: Android This issue is specific to Android

Comments

@deanhet
Copy link

deanhet commented Sep 20, 2024

Description

I'm building a metronome-like app and am using reanimated to animate a box moving to indicate a "tick" of the metronome.

I've successfully got my code to make a box bouncing back and forth across the screen in time with my measure. When I hear a click using another metronome app, I see the box hit a side of the view.
This works perfectly on iOS, when I sync it with an external click, it never falls out of sync. However on Android it doesn't take long before it wavers off and the click is nowhere near in sync. That is to say that instead of the box travelling across the screen every 1000ms, it drifts to more.

I've boiled down the code to a bare minimum use-case, I think (hope) there's nothing in there that should be causing a slowdown like this.
I've tried on all sorts of simulators and the app just seems to drop frames and fail to keep up. The longer it's open for, the more out of sync it gets. Again, no issues at all on iOS, only Android.

The problem presents itself in dev and production builds, bridgeless and not bridgeless modes too.

Any help would be greatly appreciated 🙏

Steps to reproduce

import { useEffect, useMemo, useState } from 'react'
import { Button, Dimensions, SafeAreaView, View } from 'react-native'
import Reanimated, {
  cancelAnimation,
  Easing,
  useAnimatedStyle,
  useSharedValue,
  withRepeat,
  withTiming,
} from 'react-native-reanimated'

const SCREEN_WIDTH = Dimensions.get('screen').width

export default function App() {
  const [isPlaying, setIsplaying] = useState(false)
  const [bpm, setBpm] = useState(60)
  const intervalTime = useMemo(() => (60 / bpm) * 1000, [bpm]) // Converts BPM to milliseconds per beat

  console.log(`Should hit a wall every ${intervalTime}ms`)
  const bpmMeasureShared = useSharedValue(0)

  useEffect(() => {
    if (!isPlaying) {
      cancelAnimation(bpmMeasureShared)
      bpmMeasureShared.value = 0
    } else {
      bpmMeasureShared.value = withRepeat(
        withTiming(SCREEN_WIDTH - 50, {
          duration: intervalTime,
          easing: Easing.linear,
        }),
        0,
        true
      )
    }
  }, [isPlaying])

  const animatedStyle = useAnimatedStyle(() => {
    return {
      transform: [
        {
          translateX: bpmMeasureShared.value,
        },
      ],
    }
  }, [bpmMeasureShared])

  const togglePlaying = () => {
    setIsplaying(!isPlaying)
  }

  return (
    <SafeAreaView>
      <View style={{ flexDirection: 'row', paddingTop: 50 }}>
        <Button onPress={togglePlaying} title={isPlaying ? 'Stop' : 'Play'} />
      </View>

      <Reanimated.View
        style={[
          { width: 50, height: 50, backgroundColor: 'orange' },
          animatedStyle,
        ]}
      />
    </SafeAreaView>
  )
}

Snack or a link to a repository

See above

Reanimated version

3.15.3

React Native version

0.74.5

Platforms

Android

JavaScript runtime

Hermes

Workflow

Expo Dev Client

Architecture

Fabric (New Architecture)

Build type

None

Device

Android emulator

Device model

No response

Acknowledgements

Yes

@github-actions github-actions bot added Platform: Android This issue is specific to Android Missing repro This issue need minimum repro scenario labels Sep 20, 2024
Copy link

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

@bartlomiejbloniarz
Copy link
Contributor

Was this issue present in previous versions, or is it only on 3.15.3?

@deanhet
Copy link
Author

deanhet commented Sep 20, 2024

3.15.2 too, I just updated in hope it might fix it

@deanhet
Copy link
Author

deanhet commented Sep 20, 2024

If this info helps, I've tried my hand at not using withTiming / withRepeat at all with:

  const intervalTime = 1000
  const tickDirection = useSharedValue(1)
  const progress = useSharedValue(0)
  const startTime = useSharedValue(0)

  useFrameCallback((frameTime) => {
    if (startTime.value === 0) {
      startTime.value = frameTime.timeSincePreviousFrame
    }

    const elapsed = frameTime.timeSincePreviousFrame ?? 0 - startTime.value
    const incrementedValue = 1 / (intervalTime / elapsed)

    if (tickDirection.value > 0) {
      progress.value += incrementedValue
      if (progress.value >= 1) {
        tickDirection.value = -1
      }
    } else {
      progress.value -= incrementedValue
      if (progress.value <= 0) {
        tickDirection.value = 1
      }
    }
  })

  const animatedStyle = useAnimatedStyle(() => {
    return {
      width: 50,
      height: 50,
      backgroundColor: 'orange',
      transform: [
        {
          translateX: interpolate(
            progress.value,
            [0, 1],
            [0, SCREEN_WIDTH - 50],
            {
              extrapolateRight: Extrapolation.CLAMP,
            }
          ),
        },
      ],
    }
  }, [progress])

Exact same results as previous. iOS is rock solid, Android drifts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Missing repro This issue need minimum repro scenario Platform: Android This issue is specific to Android
Projects
None yet
Development

No branches or pull requests

2 participants