React-native-track-player: ProgressComponent slowing down the App

Created on 9 Feb 2018  路  7Comments  路  Source: react-native-kit/react-native-track-player

Hi,
I got slow performance when adding ProgressComponent. I use this component to show current position status and slider for position indicator.

And sometimes i can't interact with other component, such as my play/pause button. is this RN problem or the library?

Here is my code:

export class TrackStatus extends TrackPlayer.ProgressComponent {
  state = {
    duration: 0,
    isSeeking: false
  }
  formatTime(seconds) {
    return seconds > 3600 
    ?
      [
        parseInt(seconds / 60 / 60),
        parseInt(seconds / 60 % 60),
        parseInt(seconds % 60)
      ].join(":").replace(/\b(\d)\b/g, "0$1")
    :
      [
        parseInt(seconds / 60 % 60),
        parseInt(seconds % 60)
      ].join(":").replace(/\b(\d)\b/g, "0$1")
  }
  render () {
    TrackPlayer.getDuration().then(duration=>this.setState({duration}))
    return (
      <View>
        <View style={{flexDirection:'row',paddingHorizontal: 15,alignItems:'center'}}>
          <Text style={{color: 'white',backgroundColor:'transparent',width:40,textAlign:'center',fontSize:12}}>
            { this.state.isSeeking ? this.formatTime(this.seek) : this.formatTime(this.state.position) }
          </Text>
          <Slider 
            minimumValue          = {0}
            maximumValue          = {this.state.duration}
            thumbTintColor        = "white"
            minimumTrackTintColor = "#f06595"
            maximumTrackTintColor = "rgba(255,255,255,.8)"
            step                  = {1}
            onValueChange ={ val=>{
              TrackPlayer.pause();
              this.seek = val;
              this.setState({isSeeking:true})
            }}
            onSlidingComplete={ val=>{
              this.setState({isSeeking: false },()=> {
                TrackPlayer.seekTo(this.seek);
                this.position = this.seek;
                TrackPlayer.play();
              })
            }}
            value={this.state.isSeeking ? this.seek : this.state.position}
          />
          <Text>{this.formatTime(this.state.duration)}</Text>
        </View>
      </View>
    )
  }
}

Thanks.

Most helpful comment

  1. You don't need to retrieve the duration everytime the progress updates, use this.state.duration instead.
  2. The Slider component might be the problem here, it is being recreated every second.

You can check out an example here

All 7 comments

  1. You don't need to retrieve the duration everytime the progress updates, use this.state.duration instead.
  2. The Slider component might be the problem here, it is being recreated every second.

You can check out an example here

Thanks. Any idea how to implement the slider for seek control without slowing the app?

This is slightly unrelated, but the only slider in my app is for this progress component. Also the most-frequent crash in my Android app seems to be related to sliders...

java.lang.NullPointerException: 
  at android.animation.AnimatorSet.clone (AnimatorSet.java:690)
  at android.animation.AnimatorSet.clone (AnimatorSet.java:51)
  at android.animation.Animator$AnimatorConstantState.newInstance (Animator.java:562)
  at android.animation.Animator$AnimatorConstantState.newInstance (Animator.java:543)
  at android.content.res.ConstantState.newInstance (ConstantState.java:51)
  at android.content.res.ConstantState.newInstance (ConstantState.java:59)
  at android.animation.AnimatorInflater.loadAnimator (AnimatorInflater.java:133)
  at android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState$PendingAnimator.newInstance (AnimatedVectorDrawable.java:567)
  at android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState.inflatePendingAnimators (AnimatedVectorDrawable.java:545)
  at android.graphics.drawable.AnimatedVectorDrawable.applyTheme (AnimatedVectorDrawable.java:377)
  at android.graphics.drawable.DrawableContainer$DrawableContainerState.applyTheme (DrawableContainer.java:865)
  at android.graphics.drawable.DrawableContainer.applyTheme (DrawableContainer.java:577)
  at android.graphics.drawable.StateListDrawable.applyTheme (StateListDrawable.java:370)
  at android.graphics.drawable.AnimatedStateListDrawable.applyTheme (AnimatedStateListDrawable.java:391)
  at android.content.res.Resources.loadDrawable (Resources.java:2589)
  at android.content.res.MiuiResources.loadDrawable (MiuiResources.java:387)
  at android.content.res.TypedArray.getDrawable (TypedArray.java:872)
  at android.widget.AbsSeekBar.<init> (AbsSeekBar.java:92)
  at android.widget.SeekBar.<init> (SeekBar.java:85)
  at android.widget.SeekBar.<init> (SeekBar.java:81)
  at com.facebook.react.views.slider.ReactSlider.<init> (ReactSlider.java:56)
  at com.facebook.react.views.slider.ReactSliderManager.createViewInstance (ReactSliderManager.java:121)
  at com.facebook.react.views.slider.ReactSliderManager.createViewInstance (ReactSliderManager.java:39)
  at com.facebook.react.uimanager.ViewManager.createView (ViewManager.java:44)
  at com.facebook.react.uimanager.NativeViewHierarchyManager.createView (NativeViewHierarchyManager.java:224)
  at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute (UIViewOperationQueue.java:153)
  at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.dispatchPendingNonBatchedOperations (UIViewOperationQueue.java:1010)
  at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded (UIViewOperationQueue.java:981)
  at com.facebook.react.uimanager.GuardedFrameCallback.doFrame (GuardedFrameCallback.java:31)
  at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame (ReactChoreographer.java:136)
  at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame (ChoreographerCompat.java:107)
  at android.view.Choreographer$CallbackRecord.run (Choreographer.java:858)
  at android.view.Choreographer.doCallbacks (Choreographer.java:672)
  at android.view.Choreographer.doFrame (Choreographer.java:605)
  at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:846)
  at android.os.Handler.handleCallback (Handler.java:742)
  at android.os.Handler.dispatchMessage (Handler.java:95)
  at android.os.Looper.loop (Looper.java:154)
  at android.app.ActivityThread.main (ActivityThread.java:5523)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:739)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:629)

@ariona Also, don't setState in render method. This... TrackPlayer.getDuration().then(duration=>this.setState({duration})) will create at least one infinite loop. More if the component receives other props/store-state that change.

This issue has been inactive for a while and seems that the issue was resolved. I will now close it.

Just started using the ProgressComponent, it still retrieves position values even when the player stopped. This seems quite unnecessary or am I wrong?

@Pczek & Anyone still facing this issue. The latest 1.1.4 has this.state.position, this.state.duration, and this.state.bufferedPosition returning correctly for each Platform.

You're progress component will still update when the track player is stopped which I think is the correct behavior because those values could realistically change without the audio playing and you would want to update them.

To improve performance simply drop in a shouldComponentUpdate where ever you extend ProgressComponent

class MyProgressComponent extends ProgressComponent {
  shouldComponentUpdate(nextProps, nextState) {
    const {
      duration: prevDuration,
      position: prevPosition,
      bufferedPosition: prevBufferedPosition
    } = this.state;
    const {
      duration: nextDuration,
      position: nextPosition,
      bufferedPosition: nextBufferedPosition
    } = nextState;
    if(prevDuration !== nextDuration || prevPosition !== nextPosition || prevBufferedPosition !== nextBufferedPosition) {
      return true;
    }
    return false;
  }

 render() { ... }
}
Was this page helpful?
0 / 5 - 0 ratings