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..!!