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

Android AudioRecorder资源未正常释放导致创建失败问题求助

解决AudioRecord多次使用后资源泄漏导致创建失败的问题

我之前也碰到过一模一样的AudioRecord资源泄漏问题,你的报错日志里的createRecord returned error -1本质就是系统音频输入资源没有被正确释放,导致后续尝试创建新的AudioRecord实例时,系统没有可用资源分配给你了。重启应用能恢复,是因为重启会让系统强制回收该应用占用的所有音频资源。

先分析下你现有代码里的几个潜在问题:

  • 资源释放逻辑只在try块的末尾执行,如果循环过程中抛出异常,会直接跳去catch块,stop()和release()根本不会被调用,Recorder就会一直占用资源
  • micRunning变量如果没有用volatile修饰,多线程环境下可能出现线程不可见性问题,导致循环无法及时退出,Recorder长时间占用资源
  • 调用stop()和release()前没有检查Recorder的当前状态,可能在错误状态下调用这些方法,导致资源释放不彻底

给你几个具体的修复方案:

1. 用finally块确保资源必被释放

不管代码是否抛出异常,finally块里的逻辑都会执行,这是保证资源释放的关键:

// 确保micRunning是线程安全的,用volatile修饰
private volatile boolean micRunning = false;
private AudioRecord recorder = null;

public void startRecording() {
    try {
        int bufferSize = AudioRecord.getMinBufferSize(FREQUENCY, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT)*2;
        recorder = new AudioRecord.Builder()
            .setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION)
            .setAudioFormat(new AudioFormat.Builder()
                .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                .setSampleRate(FREQUENCY)
                .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
                .build())
            .setBufferSizeInBytes(bufferSize)
            .build();
        
        recorder.startRecording();
        micRunning = true;
        
        while (micRunning) {
            byte[] tempBuffer = new byte[bufferSize];
            int readSize = recorder.read(tempBuffer,0,bufferSize);
            // 注意:要检查read的返回值,避免处理无效数据
            if (readSize > 0) {
                byte[] ba = new Resampler().reSample(tempBuffer, 16, 8000, 16000);
                sendMicData(ba);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // 确保Recorder资源被释放
        if (recorder != null) {
            // 先检查状态,避免在未初始化的状态下调用stop
            if (recorder.getState() == AudioRecord.STATE_INITIALIZED) {
                // 还要检查是否正在录制
                if (recorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
                    recorder.stop();
                    Log.d("Mic", "Call Stop: " + recorder.getState());
                }
            }
            recorder.release();
            recorder = null; // 置为null,避免后续误操作
            Log.d("Mic", "Call Release");
            Log.d("Mic", "All done state: " + recorder);
        }
        micRunning = false;
    }
}

public void stopRecording() {
    micRunning = false;
}

2. 避免重复创建Recorder的错误逻辑

每次启动录音前,一定要确保之前的Recorder已经被完全释放:

  • 在startRecording()方法开头,先检查recorder是否不为null,如果是,先调用上面的释放逻辑
  • 不要在循环内部重复创建Recorder实例,确保一个录音周期对应一个Recorder实例

3. 检查音频资源的占用情况(调试用)

如果你还是不确定资源是否泄漏,可以在创建Recorder前后,用adb命令查看系统音频资源的占用情况:

adb shell dumpsys media.audio_flinger

在输出里查找Record Tracks相关的内容,看看有没有未被释放的录音轨道。

这样修改后,应该就能解决多次运行后创建AudioRecord失败的问题了,既保证了资源的正确释放,也避免了无效的状态调用。

内容的提问来源于stack exchange,提问作者Emil Borconi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 07:07:28