You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让MediaPlayer当前播放位置每秒更新以实现音乐进度滑块?

问题分析与修复方案

核心问题

  1. 仅单次更新播放位置:你只在MediaPlayer准备完成时调用了一次updatePlaybackState,没有持续监听播放进度变化,导致状态无法每秒更新。
  2. 滑块未绑定播放状态: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 22:30:56