Kotlin-在Recyclerview Android中使用Seekbar播放音频
我正在使用Kotlin-在Recyclerview Android中使用Seekbar播放音频,android,kotlin,android-mediaplayer,android-recyclerview,android-seekbar,Android,Kotlin,Android Mediaplayer,Android Recyclerview,Android Seekbar,我正在使用Recyclerview显示音频文件列表。在每个列表项中,我都使用Seekbar将其与音频文件的播放状态同步。现在的问题是,当我第一次点击任何列表项中的播放图标时,音频开始按需播放,但seekbar保持原样(未更改/搜索),第二次按需工作(播放音频并搜索搜索栏)。我在谷歌上搜索并尝试了几个解决方案,但找不到相关的解决方案 以下是我的适配器类中的内容: class VoiceNotesListAdapter(private val voiceNotesList: ArrayList<
Recyclerview
显示音频文件列表。在每个列表项中,我都使用Seekbar
将其与音频文件的播放状态同步。现在的问题是,当我第一次点击任何列表项中的播放图标时,音频开始按需播放,但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
}
}
class VoiceNotesListAdapter(私有val voiceNotesList:ArrayList):
RecyclerView.Adapter(){
lateinit var mediaPlayer:mediaPlayer
私有变量currentPlayingPosition=-1
私有变量seekBarUpdater=seekBarUpdater()
private var playingHolder:视图持有者?=null
override onCreateViewHolder(父级:ViewGroup,viewType:Int):ViewHolder{
val view=LayoutInflater.from(parent.context)
.充气(com.hyrthmcor.R.layout.item\u voice\u notes,父项,假)
返回视图保持器(视图)
}
重写getItemCount():Int{
返回voiceNotesList.size
}
覆盖BindViewHolder(holder:ViewHolder,位置:Int){
holder.bindVoiceItem(voiceNotesList[位置])
如果(位置==当前播放位置){
playingHolder=保持架
updatePlayingView()
}否则{
updateNonPlayingView(支架)
}
}
覆盖视图(保持架:视图保持架){
super.onViewRecycled(支架)
if(currentPlayingPosition==支架适配器位置){
updateNonPlayingView(播放文件夹)
playingHolder=null
}
}
私人娱乐更新NonPlayingView(持有者:ViewHolder?){
支架?参见kbarplayindicator?拆下Callbacks(参见kbarUpdater)
保持架?.seekBarPlayIndicator?.isEnabled=错误
保持架?.seekBarPlayIndicator?.progress=0
holder?.imgPlayPause?.setImageResource(com.hyrthcor.R.drawable.ic\u play\u black\u 24dp)
}
private fun updatePlayingView(){
playingHolder?.seekBarPlayIndicator?.isEnabled=真
playingHolder?.seekBarPlayIndicator?.max=mediaPlayer.duration
playingHolder?.seekBarPlayIndicator?.progress=mediaPlayer.currentPosition
}
趣味图层(){
如果(空!=mediaPlayer){
releaseMediaPlayer()
}
}
私有内部类SeekBarUpdater:Runnable{
覆盖趣味跑(){
如果(null!=播放文件夹){
playingHolder?.seekBarPlayIndicator?.progress=mediaPlayer.currentPosition
playingHolder?.seekBarPlayIndicator?.postDelayed(此,100)
}
}
}
内部类ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
var imgPlayPause:AppCompatImageView?=null
var seekBarPlayIndicator:AppCompatSeekBar?=null
/**
*将数据绑定/设置/更新到视图项。
*
*[voiceNote]数据类的@param voiceNote实例,从中获取数据并设置为
*各自的观点。
*/
趣味bindVoiceItem(voiceNote:voiceNote){
//查找视图
imgPlayPause=itemView.findViewById(com.hyrthcor.R.id.img\u item\u voice\u note\u play\u pause)
Seekbarplay指示器=
itemView.findViewById(com.rhythcor.R.id.seekbar\u项目\语音\音符\播放\指示器)
//Media player实例以查找音频持续时间。
val durationMediaPlayer=MediaPlayer()
durationMediaPlayer.setDataSource(voiceNote.note)
durationMediaPlayer.prepare()
//将持续时间从毫秒格式转换为MM:SS格式
val audioDuration=String.format(
“%02d:%02d”,
TimeUnit.millides.toMinutes(durationMediaPlayer.duration.toLong()),
TimeUnit.millides.toSeconds(durationMediaPlayer.duration.toLong())-
TimeUnit.MINUTES.toSeconds(TimeUnit.millides.toMinutes(durationMediaPlayer.duration.toLong()))
)
durationMediaPlayer.release()
//设置持续时间文本
itemView.findViewById(com.rhythcor.R.id.tv\u item\u voice\u note\u duration)。文本=
听力时长
//设置日期文本
itemView.findViewById(com.rhythcor.R.id.tv\u item\u voice\u note\u date)。文本=
parseTimestamp(voiceNote.createdOn.toLong()*1000,日期格式为YYYYMMDD\uHHMMSS)
//设置“单击侦听器以删除”图标
itemView.findViewById(com.hyrthcor.R.id.img\u项目\u语音\u注释\u删除)
.setOnClickListener{
//发布删除操作的主题,以便其各自的订阅者可以获取该事件
voiceNoteDeleteSubject.onNext(适配器位置)
}
imgPlayPause?.setOnClickListener{
if(适配器位置==当前播放位置){
如果(mediaPlayer.isplay){
mediaPlayer.pause()
playingHolder?.seekBarPlayIndicator?.removeCallbacks(请参阅播放时间)
playingHolder?.imgPlayPause?.setImageResource(com.rhythcor.R.drawable.ic_play_black_24dp)
}否则{
mediaPlayer.start()
播放文件夹?.seekBarPlayIndicator?.postDelayed(请参阅播放日期,100)
playingHolder?.imgPlayPause?.setImageResource(com.rhythcor.R.drawable.ic_pause_black_24dp)
}
}否则{
当前播放位置=适配器位置
如果(::mediaPlayer.isInitialized&&mediaPlayer!=null){
如果(null!=播放文件夹){