Kotlin循环未等待playSong函数执行完成问题求助
解决顺序播放歌曲的问题
你的问题核心在于普通for循环是同步执行逻辑,而MediaPlayer的播放是异步操作——调用start()后函数会立刻返回,不会等待歌曲播放完成,导致循环瞬间触发所有歌曲的播放请求。要实现播完一首再播下一首的效果,需要改用异步回调驱动或者协程挂起的方式来控制播放流程。
方案1:使用索引+播放完成回调(传统写法)
通过维护当前播放的歌曲索引,在每首歌播放完成的监听器里触发下一首的播放,实现顺序播放:
private var currentSongIndex = 0 // 假设你的songArray是存储歌曲资源ID的数组,比如arrayOf(R.raw.song1, R.raw.song2) private val songArray: IntArray = ... private var mediaPlayer: MediaPlayer? = null // 启动顺序播放 fun startSequentialPlay() { currentSongIndex = 0 playNextSong() } private fun playNextSong() { // 所有歌曲播放完毕,退出 if (currentSongIndex >= songArray.size) { return } val currentSongRes = songArray[currentSongIndex] // 创建并启动MediaPlayer mediaPlayer = MediaPlayer.create(context, currentSongRes).apply { start() // 播放完成时触发下一首 setOnCompletionListener { player -> player.release() // 释放当前播放器资源 mediaPlayer = null currentSongIndex++ playNextSong() // 递归调用播放下一首 } // 可选:添加播放错误处理 setOnErrorListener { player, _, _ -> player.release() mediaPlayer = null currentSongIndex++ playNextSong() true } } }
方案2:使用协程挂起(现代Android开发推荐)
利用Kotlin协程的挂起特性,将异步的播放操作转为同步写法,代码逻辑更直观:
import kotlinx.coroutines.suspendCoroutine import android.media.MediaPlayer // 挂起函数:播放指定歌曲,直到播放完成或出错 private suspend fun playSong(songResId: Int) = suspendCoroutine<Unit> { cont -> val mediaPlayer = MediaPlayer.create(context, songResId).apply { start() setOnCompletionListener { player -> player.release() cont.resume(Unit) // 播放完成,恢复协程 } setOnErrorListener { player, _, _ -> player.release() cont.resumeWithException(Exception("歌曲播放失败")) // 出错时抛出异常 true } } } // 在协程作用域中启动顺序播放 // 比如在Activity/Fragment中使用lifecycleScope lifecycleScope.launch { for (songRes in songArray) { try { playSong(songRes) // 协程会挂起直到当前歌曲播放完成 } catch (e: Exception) { // 处理播放错误,比如打印日志或提示用户 e.printStackTrace() } } }
对你原有代码的修正提示
- 你的
playSong函数中传入的song参数未被使用,直接写死了R.raw.song,需要改为使用传入的歌曲资源ID mediaPlayer.start缺少括号,正确写法是mediaPlayer.start()- 避免使用
!!强制非空断言,推荐用apply、let等安全调用方式,减少空指针风险
内容的提问来源于stack exchange,提问作者pop
相关产品推荐
相关产品推荐

