kotlin:Jetpack Compose 给APP添加声音(点击音效/背景音乐)

Jetpack Compose 给APP添加声音(点击音效/背景音乐)

在 Jetpack Compose 中播放声音,最常用、最简单 的方案是使用 Android 原生的 SoundPool (短音效,如点击、弹窗)和 MediaPlayer(长音频,如背景音乐)。

我给你整理了开箱即用的完整代码,直接复制就能用。


第一步:准备音频文件

  1. res 目录下创建 raw 文件夹(右键 res → New → Android Resource Directory → Resource type 选 raw
  2. 把你的音频文件(mp3 / wav 格式)放进去,例如:
    • click_sound.wav
    • bg_music.mp3

文件名只能是:小写字母、数字、下划线


方案1:短音效(点击按钮/交互)SoundPool ✅

适合点击、弹窗、反馈等短音频,延迟低、性能好。

完整 Compose 代码

kotlin 复制代码
import android.media.SoundPool
import android.content.Context
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext

// 播放点击音效
@Composable
fun PlaySoundScreen() {
    val context = LocalContext.current

    // 1. 初始化 SoundPool
    val soundPool = remember {
        SoundPool.Builder()
            .setMaxStreams(1) // 同时播放的音频数量
            .build()
    }

    // 2. 加载音频(只加载一次)
    val clickSoundId = remember {
        soundPool.load(context, R.raw.click_sound, 1)
    }

    // 3. 页面销毁时释放资源
    DisposableEffect(Unit) {
        onDispose {
            soundPool.release()
        }
    }

    // 页面布局
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Button(onClick = {
            // 播放音效:(soundID, 左音量, 右音量, 优先级, 循环, 播放速度)
            soundPool.play(clickSoundId, 1f, 1f, 1, 0, 1f)
        }) {
            Text("点击播放音效")
        }
    }
}

参数说明

  • 1f, 1f:左右音量(0.0 ~ 1.0)
  • 0:循环次数(0=不循环,-1=无限循环)
  • 1f:播放速度(0.5~2.0)

方案2:长音频(背景音乐)MediaPlayer ✅

适合背景音乐、语音播报等长音频。

完整 Compose 代码

kotlin 复制代码
import android.media.MediaPlayer
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext

// 播放背景音乐
@Composable
fun PlayBackgroundMusicScreen() {
    val context = LocalContext.current

    // 初始化 MediaPlayer
    val mediaPlayer = remember {
        MediaPlayer.create(context, R.raw.bg_music).apply {
            isLooping = true // 循环播放
            setVolume(0.5f, 0.5f) // 音量
        }
    }

    // 页面销毁时停止并释放
    DisposableEffect(Unit) {
        onDispose {
            mediaPlayer.stop()
            mediaPlayer.release()
        }
    }

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Button(onClick = { mediaPlayer.start() }) {
            Text("播放背景音乐")
        }

        Button(onClick = { mediaPlayer.pause() }) {
            Text("暂停背景音乐")
        }
    }
}

方案3:全局点击音效(整个APP点击都发声)

如果你想所有按钮点击都自动播放音效 ,可以封装一个自定义点击修饰符

kotlin 复制代码
import androidx.compose.foundation.clickable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import android.media.SoundPool

// 全局带音效的点击
@Composable
fun Modifier.clickWithSound(
    soundId: Int,
    soundPool: SoundPool,
    onClick: () -> Unit
): Modifier {
    return this.clickable {
        soundPool.play(soundId, 1f, 1f, 1, 0, 1f)
        onClick()
    }
}

使用:

kotlin 复制代码
Text(
    text = "点我有声音",
    modifier = Modifier.clickWithSound(clickSoundId, soundPool) {
        // 你的点击逻辑
    }
)

常见问题

  1. 音频没声音?

    • 检查文件是否放在 res/raw/
    • 检查音量是否打开
    • 音频文件名必须小写
  2. 报错资源找不到?

    • 重建项目:Build → Clean Project → Rebuild Project
  3. 页面退出还在响?

    • 必须用 DisposableEffect 在页面销毁时 release() 释放音频

总结

  • 短音效(点击) :用 SoundPool,延迟低
  • 长音效(背景音乐) :用 MediaPlayer
  • 音频文件放在 res/raw/
  • 页面销毁必须释放资源,避免内存泄漏

需要我帮你把音效封装成一个工具类,让整个 APP 随便调用吗?

相关推荐
逐光老顽童2 天前
Java 与 Kotlin 混合开发避坑指南:30 个真实案例实录
android·kotlin
爱勇宝2 天前
鸿蒙生态的下半场:开发者不只要能开发,还要能赚钱
android·前端·程序员
Yeyu3 天前
刷新一帧的艺术:invalidate / postInvalidate / postInvalidateOnAnimation全解析
android
潘潘潘3 天前
Android OTA 升级原理和流程介绍
android
plainGeekDev3 天前
null 判断 → Kotlin 可空类型
android·java·kotlin
plainGeekDev3 天前
getter/setter → Kotlin 属性
android·java·kotlin
Junerver3 天前
我写了一个 Compose Multiplatform 组件库,你可能会用到
kotlin·android jetpack
YXL1111YXL3 天前
Handler 消息回收与协程异步执行的时序陷阱
android
恋猫de小郭3 天前
KMP / CMP 鸿蒙版本 Beta 发布,他有什么特别之处?
android·前端·flutter
三少爷的鞋3 天前
Android 协程并发控制:别动线程池,控制好并发语义就够了
android