Search code examples
kotlinandroid-jetpack-composeexoplayerexoplayer2.x

Update Jetpack Compose Slider Progress based on ExoPlayer playing audio position


I have created a custom UI for player an audio file and I am using Exoplayer to get the file and play it. I am not using the custom controller for exoplayer and my UI has a Slider that needs to update based on the current audio position. How can I achieve this? Please help.

  var currentValue by remember { mutableStateOf(0f) }
  currentValue = mediaPlayer.getCurrentPosition()
  Slider(
            modifier = Modifier.weight(1f),
            value = currentValue ,
            onValueChange = {currentValue = it },
            valueRange = 0f.. mediaPlayer.contentDuration()
        )
               

Solution

  • According to your code, you're expecting mediaPlayer.getCurrentPosition() to trigger recomposition somehow.

    Compose can only track State object changes, which a special type created to trigger recompositions.

    When you need to work with some non Compose library, you need to search for the way to track changes. In most of old libraries there're some listeners for such case.

    In case of ExoPlayer there's no direct listener. In this issue you can see suggestion to use the listener to track isPlaying state. In Compose to work with listeners you can use DisposableEffect so when the view disappears you can remove the listener.

    And then when it's playing - call currentPosition repeatedly with some interval. As Compose is built around Coroutines, it's pretty easy to do it with LaunchedEffect:

    var currentValue by remember { mutableStateOf(0L) }
    var isPlaying by remember { mutableStateOf(false) }
    
    DisposableEffect(Unit) {
        val listener = object : Player.Listener {
            override fun onIsPlayingChanged(isPlaying_: Boolean) {
                isPlaying = isPlaying_
            }
        }
        mediaPlayer.addListener(listener)
        onDispose {
            mediaPlayer.removeListener(listener)
        }
    }
    if (isPlaying) {
        LaunchedEffect(Unit) {
            while(true) {
                currentValue = mediaPlayer.currentPosition
                delay(1.seconds / 30)
            }
        }
    }