Seekbar For MediaPlayer not Functioning Properly

20 views Asked by At

I have the app in which i want to play some musics .I have the activity called Music Activity , which have the recycler View for showing various music items .. The Adapter class for the recycler View is called MusicAdapter. The code for the MusicAdapter Class is as follows ....

      package com.lashsolutions.quotesapp
    
    import android.content.Context
    import android.media.MediaPlayer
    import android.os.Build
    import android.os.Handler
    import android.os.PowerManager
    import android.util.Log
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import android.widget.ImageView
    import android.widget.SeekBar
    import android.widget.TextView
    import android.widget.Toast
    import androidx.core.content.ContextCompat.getSystemService
    import androidx.recyclerview.widget.RecyclerView
    import java.util.*
    
    class MusicAdapter(private val context:Context , private val musicList: List<MusicDataClass>) :
        RecyclerView.Adapter<MusicAdapter.MusicViewHolder>() {
    
        private var currentPlayingPosition: Int? = null
        private var currentMediaPlayer:MediaPlayer= MediaPlayer() //media Player to store the current instance of the mediaPlayer which is playing
        private lateinit var currentPauseVisibleButton:ImageView
        private lateinit var currentPlayGoneButton:ImageView
        private var mainHandler = Handler() //store the handler to use it in the function 
                                            //stopPlaybackWhenActivityDestroyed, for retrieving it in the Music Activity and release all the media player
        private lateinit var mainUpdateSeekBar:Runnable
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MusicViewHolder {
            val itemView = LayoutInflater.from(parent.context).inflate(R.layout.music_itemgrid, parent, false)
            return MusicViewHolder(itemView)
        }
    
        override fun onBindViewHolder(holder: MusicViewHolder, position: Int) {
            val currentMusic = musicList[position]
            holder.bind(currentMusic, position)
        }
    
        override fun getItemCount() = musicList.size
    
    
        inner class MusicViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            private val tv_musicName: TextView = itemView.findViewById(R.id.tv_musicName)
            private val tv_musicDuration: TextView = itemView.findViewById(R.id.tv_musicDuration)
            private val seekBar: SeekBar = itemView.findViewById(R.id.seekBar)
            private val tv_seekBarDurationProgress:TextView = itemView.findViewById(R.id.tv_seekBarDurationProgress)
            private val tv_seekBarTotalDuration:TextView = itemView.findViewById(R.id.tv_seekBarTotalDuration)
            private val iv_play: ImageView = itemView.findViewById(R.id.iv_play)
            private val iv_pause: ImageView = itemView.findViewById(R.id.iv_pause)
    
            private  var mediaPlayer: MediaPlayer = MediaPlayer() //local scope media player in the View Holder for...mediaPlayer for all the music items seperately 
            private val handler = Handler()  //local scope handler in the View Holder for...handler for all the music items seperately 
            private var isSeekBarTracking = false
            private val SEEK_BAR_UPDATE_DELAY = 100L
    
            init {
    
                seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                    override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                        if (fromUser) {
                            mediaPlayer.seekTo(progress)
                        }
    
                        updateProgressText(progress)
                    }
    
                    override fun onStartTrackingTouch(seekBar: SeekBar?) {
                        isSeekBarTracking = true
                    }
    
                    override fun onStopTrackingTouch(seekBar: SeekBar?) {
                        isSeekBarTracking = false
                    }
                })
            }
    
            fun bind(music: MusicDataClass, position: Int) {
                tv_musicName.text = music.title
                tv_musicDuration.text = music.duration
                tv_seekBarTotalDuration.text = music.duration
    
                val durationParts = music.duration.split(":")
                val minutes = durationParts[0].toLong()
                val seconds = durationParts[1].toLong()
                val totalDuration = (minutes * 60 + seconds) * 1000
                Log.d("totalDuration", "$totalDuration")
    
                seekBar.max = totalDuration.toInt()
    
                iv_play.setOnClickListener {
                    if (position != currentPlayingPosition) {
                        Log.d("EnteredInside" , "yes.... currentPlayingPosition $currentPlayingPosition")
                        currentPlayingPosition?.let {
                            Log.d("TryingToStop" , "yes tying to stop")
                            currentMediaPlayer.pause()
                            currentPlayingPosition = null
                            currentPlayGoneButton.visibility=View.VISIBLE
                            currentPauseVisibleButton.visibility=View.GONE
    
    
                            stopSeekBarUpdate()
                        }
                        onPlayClick(music, position)
                    } else {
                        mediaPlayer.start()
                    }
    
                    iv_play.visibility = View.GONE
                    iv_pause.visibility = View.VISIBLE
    
    
                    currentPlayGoneButton=iv_play // store the play button so that when the //media player is stopped , we can make this iv_play button visible and pasue button gone
                    currentPauseVisibleButton=iv_pause //when the play button ic clicked , //the pause button is visible () and is getting stored in the currentPauseVisibleButton
                    // the pause button indicated by the currentPauseVisibleButton will be //gone and the
    
                    startSeekBarUpdate()
    
                }
    
                iv_pause.setOnClickListener {
                    onPauseClick()
                    iv_pause.visibility = View.GONE
                    iv_play.visibility = View.VISIBLE
    
                    stopSeekBarUpdate()
    
                }
    
            }
    
            private val updateSeekBar = object : Runnable {
                override fun run() {
                    if (!isSeekBarTracking) {
                          val currentPosition = mediaPlayer.currentPosition
                        seekBar.progress = currentPosition
                    }
                    handler.postDelayed(this, SEEK_BAR_UPDATE_DELAY)
    
                }
            }
    
            private fun updateProgressText(progress: Int) {
                val minutes = progress / 60000
                val seconds = (progress % 60000) / 1000
                val progressText = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds)
                tv_seekBarDurationProgress.text = progressText
            }
    
    
            private fun startSeekBarUpdate() {
                handler.post(updateSeekBar)
                mainUpdateSeekBar=updateSeekBar
                mainHandler=handler
            }
    
            private fun stopSeekBarUpdate() {
                handler.removeCallbacks(updateSeekBar)
            }
    
            private fun onPlayClick(music: MusicDataClass, position: Int) {
    
                     val  currentPosition = seekBar.progress
                    mediaPlayer.apply {
                        reset()
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            setDataSource(itemView.context.resources.openRawResourceFd(music.resourceId))
                        }
    
                        prepare()
                        start()
                        seekTo(currentPosition)
                        currentPlayingPosition = position
                        currentMediaPlayer=mediaPlayer
                    }
    
    
    
            }
    
            private fun onPauseClick() {
                mediaPlayer.pause()
    
            }
    
        }
    
        fun stopPlaybackWhenActivityDestroyed() {
            //stop and release the media player if any when the activity is destroyed by the user , without
            // stopping the media player
            currentMediaPlayer.stop()
            currentMediaPlayer.release()
    
    
            mainHandler.removeCallbacks(mainUpdateSeekBar)
    
            Toast.makeText(context, "activity destroyed and media player and stopped and wake lock released", Toast.LENGTH_LONG).show()
    
        }

}

Let me Explain all the code .... Basically in the layout of the each individual item of the recycler view , i have the name of the music , duration of the music , seekbar , play button and pause button which are shown one at a time ...when the play button is clicked , then its view is Gone and pause button becomes visible ... As you can see i have one mediaplayer variable at the global scope for storing the currently media player and also to stop this media player when the user selects any other music item to play .. With the help of the variable currentPlayingPosition , i am keeping track of the currently playing music item ..if the position for the play button is clicked is different from the current playing position , then we have to stop the media player of the currently playing item and start the media player for the new music item Via the onPlayClick() function ... If it is the same item (after the pause button is clicked and then user again presses the play button ), then simply play the same media player ... I have the runnable object to update the seek bar progress ... the problem i am facing is that when i start the music by clicking the play button , then the seek bar progresses for some time (for example 20 seconds of total duration of 2min, 12sec) and then it automatically come back to initial start position ( or start progressing from the initial zero position) ...this happens only for the first time when i play the music and then after that seekbar progresses till its completion ... Also when i pause the music for some time and when i again restarts it , it repeats the same behaviour i.e. plays for some time , comes back to the position from where i resume the play of the music and then plays to completion ....

I cant able to point where i am making the mistake ... It would be really helpful if someone can help....!! Thank You..!!

0

There are 0 answers