6

我在Debug中运行时遇到这个错误数百次,它似乎并没有影响程序,但是我该如何摆脱它呢?

我知道它可以根据其他帖子追溯到SoundPool

09-15 09:03:09.190:错误/AudioCache(34):堆大小溢出!请求大小:1052672,最大大小:1048576

4

3 回答 3

12

SoundPool is hard code the buffer size as 1M for all loaded file. So you probably will get 'heap size overflow' error when you load too much files into SoundPool. I also have this issue on a game project that will load game sound FX into SoundPool and the solution is as follow:

  1. Play long/large background music in MediaPlayer.
  2. Play short sound files in multi SoundPool instances to prevent the heap error. The sample code for multi SoundPools:


 /**
  * Multi SoundPool to prevent memory error.
  */
public class SoundPools {

private static final String TAG = "SoundPools"; private static final int MAX_STREAMS_PER_POOL = 15; private List<SoundPoolContainer> containers; public SoundPools() { containers = Collections.synchronizedList(new ArrayList<SoundPoolContainer>()); } public void loadSound(Context context, String id, String file) { Log.d(TAG, "SouldPools load sound " + file); try { for (SoundPoolContainer container : containers) { if (container.contains(id)) { return; } } for (SoundPoolContainer container : containers) { if (!container.isFull()) { container.load(context, id, file); return; } } SoundPoolContainer container = new SoundPoolContainer(); containers.add(container); container.load(context, id, file); } catch (Exception e) { Log.w(TAG, "Load sound error", e); } } public void playSound(Context context, String id, String file) { Log.d(TAG, "SouldPools play sound " + file); try { for (SoundPoolContainer container : containers) { if (container.contains(id)) { container.play(context, id, file); return; } } for (SoundPoolContainer container : containers) { if (!container.isFull()) { container.play(context, id, file); return; } } SoundPoolContainer container = new SoundPoolContainer(); containers.add(container); container.play(context, id, file); } catch (Exception e) { Log.w(TAG, "Play sound error", e); } } public void onPause() { for (SoundPoolContainer container : containers) { container.onPause(); } } public void onResume() { for (SoundPoolContainer container : containers) { container.onResume(); } } private static class SoundPoolContainer { SoundPool soundPool; Map<String, Integer> soundMap; AtomicInteger size; public SoundPoolContainer() { this.soundPool = new SoundPool(MAX_STREAMS_PER_POOL, android.media.AudioManager.STREAM_MUSIC, 0); this.soundMap = new ConcurrentHashMap<String, Integer>(MAX_STREAMS_PER_POOL); this.size = new AtomicInteger(0); } public void load(Context context, String id, String file) { try { this.size.incrementAndGet(); soundMap.put(id, soundPool.load(context.getAssets().openFd(file), 1)); } catch (Exception e) { this.size.decrementAndGet(); Log.w(TAG, "Load sound error", e); } } public void play(Context context, String id, String file) { android.media.AudioManager audioManager = (android.media.AudioManager) context .getSystemService(Context.AUDIO_SERVICE); final int streamVolume = audioManager.getStreamVolume(android.media.AudioManager.STREAM_MUSIC); Integer soundId = soundMap.get(id); if (soundId == null) { soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { @Override public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { soundPool.play(sampleId, streamVolume, streamVolume, 1, 0, 1f); } }); try { this.size.incrementAndGet(); soundPool.load(context.getAssets().openFd(file), 1); } catch (IOException e) { this.size.decrementAndGet(); Log.w(TAG, "Load/Play sound error", e); } } else { try { soundPool.play(soundId, streamVolume, streamVolume, 1, 0, 1f); } catch (Exception e) { Log.w(TAG, "Play sound error", e); } } } public boolean contains(String id) { return soundMap.containsKey(id); } public boolean isFull() { return this.size.get() >= MAX_STREAMS_PER_POOL; } public void onPause() { try { soundPool.autoPause(); } catch (Exception e) { Log.w(TAG, "Pause SoundPool error", e); } } public void onResume() { try { soundPool.autoResume(); } catch (Exception e) { Log.w(TAG, "Resume SoundPool error", e); } } } }

于 2013-03-11T04:39:59.650 回答
0

也许您的媒体资源太大而无法使用 soundpool。Soundpool 只播放短音效。在 Soundpool API 上,没有关于使用 soundpool 播放资源的最大值的规范,但是如果您使用它,则只播放简短的音效,例如射击游戏中的短暂爆炸。如果这是您的问题,您应该使用 MediaPlayer 播放声音。

于 2012-11-18T19:42:50.477 回答
0

此错误不可能与堆大小有关,因为没有任何设备具有如此小的堆 1052672 ~ 1Mb.,而是与SoundPool缓冲区大小有关。 内存SoundPool中的原始数据硬编码限制为 1Mb 。PCM_16此限制适用于您加载到内存中的每个声音,而不适用于每个声音的总和SoundPool。所以投票最多的答案SoundPools是非常错误的!

让我介绍一下SoundPoolCompat哪些AudioTrack在引擎盖下使用并有自定义bufferSize。指定缓冲区内的所有数据都将被加载到内存中,并像SoundPool这样以很小的延迟播放。所有超过该值的数据bufferSize都将按需加载(这会增加延迟,类似于MediaPlayer)。Api 与 非常相似SoundPool,还添加了从 Uri 加载声音的功能(例如 gdrive)。并且有一种playOnce方法,文件播放后将卸载所有资源。

implementation 'com.olekdia:sound-pool:3.0.2'

https://gitlab.com/olekdia/common/libraries/sound-pool

于 2019-11-12T08:10:31.683 回答