SoundPool内存不足?

时间:2018-11-02 15:05:26

标签: android

我有以下课程。

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)


    }

1 个答案:

答案 0 :(得分:0)

是的,假设您加载了足够的独特声音,最终将耗尽内存。 SoundPool以未压缩的形式存储加载的声音。并且,必须将它们保持在这种状态,因为play()请求可能随时出现(据它所知)。如果没有明确调用release()unload()SoundPool将不会释放声音。

再说一次,如果您没有很多声音,那么您可能不会用完内存,因为短的声音片段相对较小。

还要注意,如果您两次将相同的资源ID传递给SoundLoadManager.load(),则您的代码将覆盖现有的声音ID(soundPoolMap),这意味着您永远无法为此调用unload()特殊的声音。也许SoundPool很聪明,不会两次加载声音,它只是返回原始的声音ID;我不知道。我必须对其进行测试。

因此,即使反复播放(即使您从未调用unload()也是如此),即使您的声音文件数量很少,最终也可能会耗尽内存。

  

还是因为它是在函数内部创建声音而我不必担心它?

不正确!这些不是局部变量。借助SoundPool对象,您的声音的作用范围将更大。该功能与它无关。