项目中,需要添加点击或者状态回调的音效。
Android 有专门用于实现音效播放的类,就是 SoundPool 。
1 工具类封装
共四种音效,更多可在 init 中 自行添加。
/**
* <pre>
* author : jake
* time : 2019/01/10
* function : 音效管理类
* version: 1.3.0
* </pre>
*/
class SoundPoolManager {
companion object {
private var instance: SoundPoolManager? = null
get() {
if (field == null) {
field = SoundPoolManager()
}
return field
}
@Synchronized
fun get(): SoundPoolManager {
return instance!!
}
const val TASK_CLICK = 1
const val TASK_SUCCESS = 2
const val TASK_WRONG = 3
const val TASK_REWARD = 4
}
private var soundPool: SoundPool = SoundPool(4, AudioManager.STREAM_MUSIC, 0)
private var sourcesMap = HashMap<Int, Int>()
init {
sourcesMap[TASK_CLICK] = soundPool.load(RiseApp.mContext, R.raw.click, 1)
sourcesMap[TASK_SUCCESS] = soundPool.load(RiseApp.mContext, R.raw.success, 1)
sourcesMap[TASK_WRONG] = soundPool.load(RiseApp.mContext, R.raw.wrong, 1)
sourcesMap[TASK_REWARD] = soundPool.load(RiseApp.mContext, R.raw.reward, 1)
}
fun play(type: Int) {
// 防止type不存在
if (sourcesMap[type] != null) {
soundPool.play(sourcesMap[type]!!, 1.0f, 1.0f, 0, 0, 1.0f)
}
}
}
在触发的地方,直接使用即可
SoundPoolManager.get().play(SoundPoolManager.TASK_CLICK)
2 音效停止播放(2019.4.23)
头一次遇到还要音效播一半,还要停止的。(音效比较多,且比较长,多次点击重复混合播放)
按照经验,肯定是通过 url 来判断是停止播放,还是开始播放新音效(两次传入相同则停止,否则则播放新的),然而发现并不生效。
后来想到,因为是一个 音效对象池,是不是播放第一个音效和播放第二个音效用不是同一个对象,从而导致调用停止方法无效的?
就是这个原因
当我们调用下面方法播放音效时,其返回值就是当前播放音效的 对象ID,且每次都不一样
soundPool.play(sourcesMap[path]!!, 1.0f, 1.0f, 0, 0, 1.0f)
所以我们只需要存储一下,上一次播放音效时的 对象ID ,然后在调用 stop 方法时,传入 对象ID 即可停止播放音效。
存储上次播放时的 音效对象ID
lastSound = soundPool.play(sourcesMap[path]!!, 1.0f, 1.0f, 0, 0, 1.0f)
停止时传入
soundPool.stop(lastSound)
由于,后来项目中用的不是打在APK 中的本地音效,而是下载到设备特定目录的音频文件,还有一些其他对应关系,故又重新封装了新的工具类,如下:
/**
* <pre>
* author : jake
* time : 2019/03/10
* function : 音效管理类
* version: 1.0
* </pre>
*
* 根据下载到本地的音效路径,播放音效
*
* 在音效下载完毕后,会调用初始化方法 LibrarySoundsManager
*
*/
class LibrarySoundPoolManager {
companion object {
private var instance: LibrarySoundPoolManager? = null
get() {
if (field == null) {
field = LibrarySoundPoolManager()
}
return field
}
@Synchronized
fun get(): LibrarySoundPoolManager {
return instance!!
}
private var soundPool: SoundPool = SoundPool(37, AudioManager.STREAM_MUSIC, 0)
private var sourcesMap = HashMap<String, Int>()
private var lastSound = 0
}
/**
* 预加载 图书馆音效资源
*
* 调用此方法时,证明图书馆音效资源已经下载完毕
*/
fun init(content: String) {
/**
* 获取前端数据,并解析
*/
val json = JSONObject(content)
val path = json["path"].toString()
val data = path.split("^")
if (data != null && data.size > 0) {
for (item in data) {
if (!item.isEmpty() && sourcesMap[RiseWebPath.LibraryWebKey.plus("/sounds/").plus(item)] == null) {
sourcesMap[RiseWebPath.LibraryWebKey.plus("/sounds/").plus(item)] = soundPool.load("${RisePath.libraryDir}/sounds/$item", 1)
}
}
}
}
/**
* 根据下载到本地的音效路径,播放音效
*/
fun play(path: String) {
if (!path.isEmpty() && sourcesMap[path] != null) {
soundPool.stop(lastSound)
lastSound = soundPool.play(sourcesMap[path]!!, 1.0f, 1.0f, 0, 0, 1.0f)
}
}
/**
* 停止播放所有音效
*/
fun stop() {
soundPool.stop(lastSound)
}
}
具体各个参数的含义,可参考这篇文章,说的蛮详细的。
うずまき ナルト
网友评论