Android MediaPlayer初始化40次后崩溃问题求助
系统信息
- 设备:联想平板M10 Plus 第三代
- RAM:3GB
- ROM:32GB
- CPU:MediaTek G80(2核A75 2.0GHz + 6核A55 1.8GHz)
- API版本:33
问题描述
我的Activity加载完成后会立即播放音频,该Activity上的控件可启动其他Activity(无论音频是否在播放)。每次离开并返回这个Activity时都会播放音频,但恰好执行40次后就无法启动了,报错如下:
MediaPlayerNative: error (1, -19)
MediaPlayer: Error (1,-19)
相关代码
private void setupMediaPlayer() throws IOException { if (mediaPlayer != null) mediaPlayer.stop(); mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioAttributes( new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributes.USAGE_MEDIA) .build()); mediaPlayer.reset(); mediaPlayer.setDataSource(getApplicationContext(), Uri.parse(mTrack)); mediaPlayer.setLooping(true); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { if (isSameTrack) currentTempo = mBundle.getInt("previousTempo"); setTempo(currentTempo); setVolume(currentVolume); mediaPlayer.seekTo(0); mp.start(); } }); } public void changeSectionButton(View view) { closeMediaPlayer(); Intent mIntent = new Intent(PlaySong.this, PickExercise.class); mIntent.putExtra("Dictionary", DictionaryManager.toString(mDictionary)); mSection = (mSection.equals("Barre")) ? "Center" : "Barre"; mIntent.putExtra("Section", mSection); startActivity(mIntent); } private void closeMediaPlayer(){ mediaPlayer.stop(); mediaPlayer.reset(); mediaPlayer.release(); mediaPlayer=null; }
解决方案
报错(1,-19)是因为系统允许的MediaPlayer实例数达到上限,本质是资源泄漏。问题出在setupMediaPlayer方法:当mediaPlayer不为null时,只调用了stop(),没释放旧实例就直接创建新的MediaPlayer,导致旧实例占用的资源无法回收,累积到40次(系统限制)就触发错误。
修改后的代码
修复setupMediaPlayer方法
private void setupMediaPlayer() throws IOException { // 先释放旧实例,再创建新的 if (mediaPlayer != null) { if (mediaPlayer.isPlaying()) { mediaPlayer.stop(); } mediaPlayer.release(); mediaPlayer = null; } mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioAttributes( new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributes.USAGE_MEDIA) .build()); mediaPlayer.setDataSource(getApplicationContext(), Uri.parse(mTrack)); mediaPlayer.setLooping(true); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { if (isSameTrack) currentTempo = mBundle.getInt("previousTempo"); setTempo(currentTempo); setVolume(currentVolume); mp.seekTo(0); mp.start(); } }); // 异步准备音频,配合OnPreparedListener完成播放 mediaPlayer.prepareAsync(); }
优化closeMediaPlayer方法
private void closeMediaPlayer(){ if (mediaPlayer != null) { if (mediaPlayer.isPlaying()) { mediaPlayer.stop(); } mediaPlayer.release(); mediaPlayer = null; } }
关键细节说明
- 新创建的MediaPlayer本身处于Idle状态,不需要额外调用
reset(),原代码中的该操作完全多余。 - 原代码遗漏了
prepareAsync()调用,这是MediaPlayer进入可播放状态的必要步骤,必须补充。 - 操作MediaPlayer时先判断状态(比如是否在播放),避免触发
IllegalStateException。
修改后每次创建新实例前都会彻底释放旧资源,不会出现泄漏,就能无限次正常播放音频。
内容的提问来源于stack exchange,提问作者David Orr
相关产品推荐
相关产品推荐

