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

Android SoundPool仅首次调用可播放声音,后续无输出问题求助

问题根因

  • 错误使用资源ID作为播放ID:SoundPool.load()方法执行后会返回专属的播放ID,你直接将资源ID R.raw.boo 赋值给soundId用于播放是完全错误的,首次能播放属于偶发巧合。
  • 未等待异步加载完成就调用播放:load()是异步操作,代码中触发加载后立刻执行play(),绝大多数场景下资源未加载完成,会直接触发播放失败。
  • 资源泄漏导致音频通道被占满:每次调用playThatSound都会新建一个SoundPool实例,且使用完成后没有调用release()释放底层音频资源,多次调用后系统分配的音频资源被耗尽,自然无法再播放声音,必须重启设备或重装应用才能释放被占的资源。

修复方案

核心优化逻辑

  1. 全局仅初始化一次SoundPool实例,不要每次播放都重复创建
  2. 提前加载音频资源,使用load()方法返回的ID作为播放凭证
  3. 页面/应用销毁时主动释放SoundPool资源
  4. 可选配置加载完成监听器,确保资源加载完成后再执行播放

修复后代码示例

import android.media.AudioAttributes
import android.media.SoundPool

// 全局SoundPool实例,建议在Activity/ViewModel初始化阶段创建
private lateinit var soundPool: SoundPool
// 存储音频标识与对应加载完成的播放ID
private val soundCache = hashMapOf<String, Int>()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 使用官方推荐的Builder方式初始化SoundPool,兼容Android 5.0+系统
    val audioAttrs = AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
        .build()
    soundPool = SoundPool.Builder()
        .setMaxStreams(6)
        .setAudioAttributes(audioAttrs)
        .build()

    // 提前加载所需音频,保存返回的播放ID
    soundCache["boo"] = soundPool.load(baseContext, R.raw.boo, 1)

    // 可选配置加载完成监听,避免未加载完成就播放
    soundPool.setOnLoadCompleteListener { _, _, status ->
        if (status == 0) {
            // 音频加载完成,可正常调用播放方法
        }
    }
}

private fun playThatSound(sound: String) {
    val playId = soundCache[sound] ?: return
    soundPool.play(playId, 1F, 1F, 0, 0, 1F)
}

// 页面销毁时主动释放资源
override fun onDestroy() {
    super.onDestroy()
    soundPool.release()
}

额外注意

SoundPool本身设计用于播放短音效,官方推荐音频大小不超过100KB、时长不超过10s,你当前使用的213KB的mp3可以先做压缩处理,避免出现加载异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 11:48:03