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

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()
        }
    }
}

对你原有代码的修正提示

  1. 你的playSong函数中传入的song参数未被使用,直接写死了R.raw.song,需要改为使用传入的歌曲资源ID
  2. mediaPlayer.start缺少括号,正确写法是mediaPlayer.start()
  3. 避免使用!!强制非空断言,推荐用apply、let等安全调用方式,减少空指针风险

内容的提问来源于stack exchange,提问作者pop

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:40:47