You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
    }
}

关键细节说明

  1. 新创建的MediaPlayer本身处于Idle状态,不需要额外调用reset(),原代码中的该操作完全多余。
  2. 原代码遗漏了prepareAsync()调用,这是MediaPlayer进入可播放状态的必要步骤,必须补充。
  3. 操作MediaPlayer时先判断状态(比如是否在播放),避免触发IllegalStateException。

修改后每次创建新实例前都会彻底释放旧资源,不会出现泄漏,就能无限次正常播放音频。

内容的提问来源于stack exchange,提问作者David Orr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 11:55:30