如何让MediaPlayer当前播放位置每秒更新以实现音乐进度滑块?
问题分析与修复方案
核心问题
- 仅单次更新播放位置:你只在MediaPlayer准备完成时调用了一次
updatePlaybackState,没有持续监听播放进度变化,导致状态无法每秒更新。 - 滑块未绑定播放状态:UI中的WavySlider硬编码了
value = 1000f,没有关联到playingSongCurrentPosition的值,即便状态更新,滑块也不会同步变化。
修复步骤
1. 添加定时任务持续更新播放位置
在MediaPlayer启动后,通过协程定时(每秒)获取当前播放位置并更新状态,同时在播放停止时取消任务避免内存泄漏。
修改ViewModel代码:
// 在ViewModel中新增协程Job变量 private var playbackUpdateJob: Job? = null fun onEvent(event: MusicPlayerUiEvents) { when (event) { is MusicPlayerUiEvents.PlaySong -> { // 原有逻辑... mediaPlayer?.setOnPreparedListener { mediaPlayer -> mediaPlayer.seekTo(state.value.playingSongCurrentPosition.value) mediaPlayer.start() setSongDuration(mediaPlayer.duration) // 启动每秒更新任务 playbackUpdateJob = viewModelScope.launch { while (mediaPlayer.isPlaying) { updatePlaybackState(mediaPlayer.currentPosition) delay(1000) // 每秒更新一次进度 } } Log.d("check for currentD_VM","${state.value.playingSongCurrentPosition.value}") } mediaPlayer?.setOnCompletionListener { mediaPlayer -> playbackUpdateJob?.cancel() // 播放结束时取消任务 // 原有结束逻辑... } } } } // ViewModel销毁时清理资源 override fun onCleared() { super.onCleared() playbackUpdateJob?.cancel() mediaPlayer?.release() }
2. 绑定滑块与播放状态
修改UI层代码,让滑块的value关联到playingSongCurrentPosition,同时支持拖动滑块跳转播放进度:
Box( modifier = Modifier .padding(vertical = 80.dp, horizontal = 20.dp) .fillMaxWidth() .height(20.dp) ) { WavySlider( valueRange = 0f..state.playingSongDuration.value.toFloat(), value = state.playingSongCurrentPosition.value.toFloat(), onValueChange = { newPosition -> // 拖动滑块时同步更新播放位置 mediaPlayer?.seekTo(newPosition.toInt()) updatePlaybackState(newPosition.toInt()) }, waveLength = 25.dp, waveHeight = 10.dp, waveVelocity = 15.dp to WaveDirection.HEAD, waveThickness = 4.dp, trackThickness = 4.dp, incremental = false, ) }
3. 优化状态类(可选)
你的MusicPlayerStates使用var MutableState的写法不够符合Compose最佳实践,建议改为val类型的原始数据,简化状态更新逻辑:
data class MusicPlayerStates( val playingSongCurrentPosition: Int = 0, val playingSongDuration: Int = 0, val isSongPlaying: Boolean = false, // other code )
对应的更新方法简化为:
private fun updatePlaybackState(currentPosition: Int) { _musicPlayerState.update { it.copy(playingSongCurrentPosition = currentPosition) } } private fun setSongDuration(duration: Int) { _musicPlayerState.update { it.copy(playingSongDuration = duration) } }
额外注意事项
- 确保导入
androidx.lifecycle.viewModelScope,让协程随ViewModel生命周期自动管理。 - 若实现暂停/播放切换功能,需同步启动/取消定时更新任务,避免状态异常。
内容的提问来源于stack exchange,提问作者IYCS
相关产品推荐
相关产品推荐

