Я использую Recyclerview
, чтобы показать список аудио-файлов. В каждом элементе списка я использовал Seekbar
, чтобы синхронизировать его с состоянием воспроизведения аудио-файла. Теперь проблема заключается в том, что когда я в первый раз нажимаю на значок воспроизведения в любом элементе списка, звук начинает воспроизводиться по желанию, но панель поиска остается без изменений (она не изменяется / не ищет), второй раз работает по желанию (проигрывает аудио, а также ищет панель поиска). Я нашел и попробовал несколько решений из здесь , здесь , но не могу найти подходящее решение.
Вот что у меня есть в классе адаптеров:
class VoiceNotesListAdapter(private val voiceNotesList: ArrayList<VoiceNote>) :
RecyclerView.Adapter<VoiceNotesListAdapter.ViewHolder>() {
lateinit var mediaPlayer: MediaPlayer
private var currentPlayingPosition = -1
private var seekBarUpdater = SeekBarUpdater()
private var playingHolder: ViewHolder? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(com.rhythmcor.R.layout.item_voice_notes, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return voiceNotesList.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindVoiceItem(voiceNotesList[position])
if (position == currentPlayingPosition) {
playingHolder = holder
updatePlayingView()
} else {
updateNonPlayingView(holder)
}
}
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (currentPlayingPosition == holder.adapterPosition) {
updateNonPlayingView(playingHolder)
playingHolder = null
}
}
private fun updateNonPlayingView(holder: ViewHolder?) {
holder?.seekBarPlayIndicator?.removeCallbacks(seekBarUpdater)
holder?.seekBarPlayIndicator?.isEnabled = false
holder?.seekBarPlayIndicator?.progress = 0
holder?.imgPlayPause?.setImageResource(com.rhythmcor.R.drawable.ic_play_black_24dp)
}
private fun updatePlayingView() {
playingHolder?.seekBarPlayIndicator?.isEnabled = true
playingHolder?.seekBarPlayIndicator?.max = mediaPlayer.duration
playingHolder?.seekBarPlayIndicator?.progress = mediaPlayer.currentPosition
}
fun stopPlayer() {
if (null != mediaPlayer) {
releaseMediaPlayer()
}
}
private inner class SeekBarUpdater : Runnable {
override fun run() {
if (null != playingHolder) {
playingHolder?.seekBarPlayIndicator?.progress = mediaPlayer.currentPosition
playingHolder?.seekBarPlayIndicator?.postDelayed(this, 100)
}
}
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var imgPlayPause: AppCompatImageView? = null
var seekBarPlayIndicator: AppCompatSeekBar? = null
/**
* Binds/Sets/Updates data to the view-item.
*
* @param voiceNote Instance of [VoiceNote] data class to get the data from it and set to
* respective view.
*/
fun bindVoiceItem(voiceNote: VoiceNote) {
// Find views
imgPlayPause = itemView.findViewById<AppCompatImageView>(com.rhythmcor.R.id.img_item_voice_note_play_pause)
seekBarPlayIndicator =
itemView.findViewById<AppCompatSeekBar>(com.rhythmcor.R.id.seekbar_item_voice_note_play_indicator)
// Media player instance to find the audio duration.
val durationMediaPlayer = MediaPlayer()
durationMediaPlayer.setDataSource(voiceNote.note)
durationMediaPlayer.prepare()
// Convert duration from Millisecond format to MM:SS format
val audioDuration = String.format(
"%02d : %02d",
TimeUnit.MILLISECONDS.toMinutes(durationMediaPlayer.duration.toLong()),
TimeUnit.MILLISECONDS.toSeconds(durationMediaPlayer.duration.toLong()) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(durationMediaPlayer.duration.toLong()))
)
durationMediaPlayer.release()
// Sets Duration text
itemView.findViewById<AppCompatTextView>(com.rhythmcor.R.id.tv_item_voice_note_duration).text =
audioDuration
// Sets Date text
itemView.findViewById<AppCompatTextView>(com.rhythmcor.R.id.tv_item_voice_note_date).text =
parseTimestamp(voiceNote.createdOn.toLong() * 1000, DATE_FORMAT_YYYYMMDD_HHMMSS)
// Set the click listener to delete icon
itemView.findViewById<AppCompatImageView>(com.rhythmcor.R.id.img_item_voice_note_delete)
.setOnClickListener {
// Publish subject for delete action so their respective subscriber can fetch that event
voiceNoteDeleteSubject.onNext(adapterPosition)
}
imgPlayPause?.setOnClickListener {
if (adapterPosition == currentPlayingPosition) {
if (mediaPlayer.isPlaying) {
mediaPlayer.pause()
playingHolder?.seekBarPlayIndicator?.removeCallbacks(seekBarUpdater)
playingHolder?.imgPlayPause?.setImageResource(com.rhythmcor.R.drawable.ic_play_black_24dp)
} else {
mediaPlayer.start()
playingHolder?.seekBarPlayIndicator?.postDelayed(seekBarUpdater, 100)
playingHolder?.imgPlayPause?.setImageResource(com.rhythmcor.R.drawable.ic_pause_black_24dp)
}
} else {
currentPlayingPosition = adapterPosition
if (::mediaPlayer.isInitialized && mediaPlayer != null) {
if (null != playingHolder) {
updateNonPlayingView(playingHolder)
}
mediaPlayer.release()
}
playingHolder = this
startMediaPlayer(voiceNote.note)
}
updatePlayingView()
}
}
}
private fun startMediaPlayer(audioPath: String) {
mediaPlayer = MediaPlayer()
mediaPlayer.setDataSource(audioPath)
mediaPlayer.setOnPreparedListener {
mediaPlayer.start()
playingHolder?.seekBarPlayIndicator?.postDelayed(seekBarUpdater, 100)
playingHolder?.imgPlayPause?.setImageResource(com.rhythmcor.R.drawable.ic_pause_black_24dp)
}
mediaPlayer.setOnErrorListener { mp, what, extra -> true }
mediaPlayer.prepareAsync()
mediaPlayer.setOnCompletionListener {
releaseMediaPlayer()
}
}
private fun releaseMediaPlayer() {
if (null != playingHolder) {
updateNonPlayingView(playingHolder)
}
mediaPlayer.release()
currentPlayingPosition = -1
}
}
Любая помощь будет оценена.
Спасибо.