我有以下课程。
class SoundLoadManager(val ctx:Context) {
var scheduled = 0
var loaded = 0
val sndPool: SoundPool
val soundPoolMap = mutableMapOf<Int,Int>()
init {
sndPool =
if (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.LOLLIPOP) {
SoundPool.Builder()
.setMaxStreams(10)
.setAudioAttributes(
AudioAttributes.Builder()
.setUsage(
AudioAttributes.USAGE_MEDIA)
.setContentType(
AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
).build()
} else {
SoundPool(10,
AudioManager.STREAM_MUSIC,
100)
}
sndPool.setOnLoadCompleteListener({
sndPool, sampleId, status ->
if(status != 0) {
Log.e("LOG",
"Sound could not be loaded")
} else {
Log.i("LOG", "Loaded sample " +
sampleId + ", status = " +
status)
}
loaded++
})
}
fun load(resourceId:Int) {
scheduled++
soundPoolMap[resourceId] =
sndPool.load(ctx, resourceId, 1)
}
fun allLoaded() = scheduled == loaded
fun play(rsrcId: Int, loop: Boolean):Int {
return soundPoolMap[rsrcId]?.run {
val audioManager = ctx.getSystemService(
Context.AUDIO_SERVICE) as AudioManager
val curVolume = audioManager.
getStreamVolume(
AudioManager.STREAM_MUSIC)
val maxVolume = audioManager.
getStreamMaxVolume(
AudioManager.STREAM_MUSIC)
val leftVolume = 1f * curVolume / maxVolume
val rightVolume = 1f * curVolume / maxVolume
val priority = 1
val noLoop = if(loop) -1 else 0
val normalPlaybackRate = 1f
sndPool.play(this, leftVolume, rightVolume,
priority, noLoop, normalPlaybackRate)
} ?: -1
}
}
并按如下方式利用它。
fun playHarmonicInterval(baseInterval: String, scaleDegree: String? ){
soundLoadManager.load(getResources().getIdentifier(baseInterval, "raw", getPackageName()));
soundLoadManager.load(getResources().getIdentifier(scaleDegree, "raw", getPackageName()))
// more ...
timer = Timer()
timer.schedule(object : TimerTask() {
override fun run() {
if(soundLoadManager.allLoaded()){
soundLoadManager.play(getResources().getIdentifier(baseInterval, "raw", getPackageName()), false)
soundLoadManager.play(getResources().getIdentifier(scaleDegree, "raw", getPackageName()), false)
timer.cancel();
}
}
}, 0, 100)
}
我的问题是我是否需要担心我的SoundLoadManager以这种方式占用大量内存并导致应用程序崩溃。还是因为它在函数内部创建声音,所以我不必担心它?
在下面的响应之后,我将代码更新为以下内容。看来还是可以的。
fun playHarmonicInterval(baseInterval: String, scaleDegree: String? ){
soundLoadManager = SoundLoadManager(this)
var value1 = soundLoadManager.load(getResources().getIdentifier(baseInterval, "raw", getPackageName()));
var value2 = soundLoadManager.load(getResources().getIdentifier(scaleDegree, "raw", getPackageName()))
timer = Timer()
timer.schedule(object : TimerTask() {
override fun run() {
if(soundLoadManager.allLoaded()){
soundLoadManager.play(getResources().getIdentifier(baseInterval, "raw", getPackageName()), false)
soundLoadManager.play(getResources().getIdentifier(scaleDegree, "raw", getPackageName()), false)
timer.cancel();
soundLoadManager.sndPool?.release()
soundLoadManager.sndPool = null;
}
}
}, 0, 100)
}
答案 0 :(得分:0)
是的,假设您加载了足够的独特声音,最终将耗尽内存。 SoundPool
以未压缩的形式存储加载的声音。并且,必须将它们保持在这种状态,因为play()
请求可能随时出现(据它所知)。如果没有明确调用release()
或unload()
,SoundPool
将不会释放声音。
再说一次,如果您没有很多声音,那么您可能不会用完内存,因为短的声音片段相对较小。
还要注意,如果您两次将相同的资源ID传递给SoundLoadManager.load()
,则您的代码将覆盖现有的声音ID(soundPoolMap
),这意味着您永远无法为此调用unload()
特殊的声音。也许SoundPool
很聪明,不会两次加载声音,它只是返回原始的声音ID;我不知道。我必须对其进行测试。
因此,即使反复播放(即使您从未调用unload()
也是如此),即使您的声音文件数量很少,最终也可能会耗尽内存。
还是因为它是在函数内部创建声音而我不必担心它?
不正确!这些不是局部变量。借助SoundPool
对象,您的声音的作用范围将更大。该功能与它无关。