Home > Software engineering >  Atomic Boolean on Seekbar - Android
Atomic Boolean on Seekbar - Android

Time:10-03

I am using coroutine to update 2 textviews and a seekbar for my musicplayer app

 private suspend fun displayTime(misc: Long) {
       // While the coroutine is running and has not been canceled by its parent
       while (coroutineContext.isActive) {

           withContext(Dispatchers.Main) {
               binding.tvPlayed.text =  convertTime(mediaPlayer.currentPosition)
               binding.tvRemaining.text =  convertTime(mediaPlayer.duration -  mediaPlayer.currentPosition)
               binding.seekBar.progress = mediaPlayer.currentPosition
           }

seekbar

private fun initializeSeekBar(){
       binding.seekBar.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{
           override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
           }
           override fun onStartTrackingTouch(seekBar: SeekBar?) {
           }

           override fun onStopTrackingTouch(seekBar: SeekBar?) {
           mediaPlayer.seekTo(seekBar!!.progress)
           }
       })
       binding.seekBar.progress =0
       binding.seekBar.max = mediaPlayer.duration

I was told that I could improve my code if I use atomic boolean when the user modify the seekbar.

val userModifyingSeekBar = AtomicBoolean(false)

Right now the seekbar jitters when I hold it. Will introduce atomic boolean eliminate the jitter here?

CodePudding user response:

You should use a Boolean to disable the media player from updating the seek bar while the user is dragging it. But it does not have to be an AtomicBoolean since you are only working with the main thread. The seek bar listener is called on the main thread, and your coroutine is always in the main dispatcher when it's checking this Boolean (below example) and updating the seek bar.

private var isUserDraggingSeekBar: Boolean = false

private suspend fun displayTime(misc: Long) {
       // While the coroutine is running and has not been canceled by its parent
       while (coroutineContext.isActive) {

           withContext(Dispatchers.Main) {
               binding.tvPlayed.text =  convertTime(mediaPlayer.currentPosition)
               binding.tvRemaining.text =  convertTime(mediaPlayer.duration -  mediaPlayer.currentPosition)
               if (!isUserDraggingSeekBar) {
                   binding.seekBar.progress = mediaPlayer.currentPosition
               }
           }
private fun initializeSeekBar(){
       binding.seekBar.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{
           override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
           }
           override fun onStartTrackingTouch(seekBar: SeekBar) {
               isUserDraggingSeekBar = true
           }

           override fun onStopTrackingTouch(seekBar: SeekBar) {
               mediaPlayer.seekTo(seekBar.progress)
               isUserDraggingSeekBar = false
           }
       })
       binding.seekBar.progress =0
       binding.seekBar.max = mediaPlayer.duration

You can mark the seekBar parameter as non-nullable in the listener functions. The only reason they are marked nullable when the IDE generates the listener for you is that the code is coming from Java and doesn't have nullability annotations on it. Android Studio/IntelliJ IDEA use a nullable parameter in this situation to be on the safe side. But the SeekBar will never pass null to these functions, so they are safe to be treated as non-nullable.

  • Related