当停止MediaRecorder时,为什么会出现IllegalStateException?

6
为了更好地了解Android中的音频录制和播放,我实现了一个克隆代码,它与android dev教程中的代码相同https://developer.android.com/guide/topics/media/mediarecorder#sample-code
启动录制时没有出现任何错误,但我尚未验证是否实际进行了任何录制。然后当我停止录制时,应用程序崩溃到先前的活动,并在随后的尝试中弹出“应用程序一直崩溃”的对话框并退出应用程序。
我在AndroidManifest中有<uses-permission android:name="android.permission.RECORD_AUDIO" />
private void onRecord(boolean start) {
        if (start) {
            startRecording();
        } else {
            stopRecording();   // Line 53 //
        }
    }

private void startRecording() {
        recorder = new MediaRecorder();
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        recorder.setOutputFile(fileName);
        System.out.println(fileName);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

        try {
            recorder.prepare();
        } catch (IOException e) {
            Log.e(LOG_TAG, "prepare() failed");
            //e.printStackTrace();
        }
    }

private void stopRecording() {
        recorder.stop();       // Line 98 //
        recorder.release();
        recorder = null;
    }

class RecordButton extends AppCompatButton {
        boolean mStartRecording = true;

        OnClickListener clicker = new OnClickListener() {
            public void onClick(View v) {
                onRecord(mStartRecording);
                if(mStartRecording) {
                    setText(R.string.stop_recording);
                } else {
                    setText(R.string.start_recording);
                }
                mStartRecording = !mStartRecording;
            }
        };

        public RecordButton(Context ctx){
            super(ctx);
            setText(R.string.start_recording);
            setOnClickListener(clicker);
        }
    }

Logcat输出:

2020-02-14 10:57:09.789 23619-23619/? E/Zygote: accessInfo : 1
2020-02-14 10:57:09.820 23619-23619/? E/.xxxxxx.xxxxxx: Unknown bits set in runtime_flags: 0x8000
2020-02-14 10:57:12.925 23619-23619/xx.xxxxxxx.xxxxxx.xxxxxxx E/MediaRecorder: stop called in an invalid state: 8
2020-02-14 10:57:12.927 23619-23619/xx.xxxxxxx.xxxxxx.xxxxxxx E/AndroidRuntime: FATAL EXCEPTION: main
    Process: xx.xxxxxxx.xxxxxx.xxxxxxx, PID: 23619
    java.lang.IllegalStateException
        at android.media.MediaRecorder._stop(Native Method)
        at android.media.MediaRecorder.stop(MediaRecorder.java:1440)
        at xx.xxxxxxx.xxxxxx.xxxxxxx.RecordActivity.stopRecording(RecordActivity.java:98)
        at xx.xxxxxxx.xxxxxx.xxxxxxx.RecordActivity.onRecord(RecordActivity.java:53)
        at xx.xxxxxxx.xxxxxx.xxxxxxx.RecordActivity.access$000(RecordActivity.java:21)
        at xx.xxxxxxx.xxxxxx.xxxxxxx.RecordActivity$RecordButton$1.onClick(RecordActivity.java:108)
        at android.view.View.performClick(View.java:7866)
        at android.widget.TextView.performClick(TextView.java:14952)
        at android.view.View.performClickInternal(View.java:7839)
        at android.view.View.access$3600(View.java:886)
        at android.view.View$PerformClick.run(View.java:29363)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:237)
        at android.app.ActivityThread.main(ActivityThread.java:7811)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1076)

我可以提供任何相关的额外代码或细节,如果需要的话。
编辑 请求以下权限:
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case REQUEST_RECORD_AUDIO_PERMISSION:
                permissionToRecordAccepted  = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                break;
        }
        if (!permissionToRecordAccepted ) finish();

    }

在onCreate()中:

ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION);

编辑2 * 我已验证录音文件正在创建,但大小为0 B


先发布它,然后停止它。 - Kuvonchbek Yakubov
通常情况下,我们似乎想避免回收正在运行的操作,但我还是尝试了一下 - 仍然在 recorder.stop() 上崩溃。 - DataMeta
你请求许可吗? - Kuvonchbek Yakubov
是的,已经在帖子中添加了编辑权限代码。 - DataMeta
@DataMeta 检查一下我的答案,并按照我所提到的去做,问题就会被解决了。 - A Farmanbar
显示剩余2条评论
1个回答

5

媒体播放器

在下面的流程图中,stop() 的有效状态为 {Prepared, Started, Stopped, Paused, PlaybackCompleted}。其他状态(Idle、Initialized、Error)不是有效状态,因此调用 stop() 会抛出 IllegalStateException 异常。

enter image description here

因此,我们应该为MediaPlayer设置状态监听器来确保状态。因为 setOnPreparedListener 早于 playerPrepared 状态初始化,所以我们可以安全地停止播放器。

...
boolean isPrepared = false;
...
recorder.setOnPreparedListener ....
{
...
isPrepared = true;
...
}
...
private void stopRecording() {
    if(isPrepared){
        player.stop();  
        ...
    }
}

我对代码进行了概述以便更好的理解。

媒体记录器

在下面的流程图中,只有在录制状态下才能使用stop()。否则,调用stop()将抛出IllegalStateException异常。

enter image description here

为了安全地停止或释放记录器资源,我们必须确保记录器已经启动。

recorder.start();   // Recording is now started 

针对你的特定代码
boolean isRecording = false;
private void startRecording() {
        recorder = new MediaRecorder();
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        recorder.setOutputFile(fileName);
        System.out.println(fileName);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

        try {
            recorder.prepare();
            recorder.start();
            isRecording = true;
        } catch (IOException e) {
            Log.e(LOG_TAG, "prepare() failed");
            //e.printStackTrace();
        }
}
....
private void stopRecording() {
    if(isRecording){
        recorder.stop();  
    }
    recorder.reset();   // You can reuse the object by going back to setAudioSource() step
    recorder.release(); // Now the object cannot be reused
    isRecording = false;
}

如果我们处于录制状态,则停止并释放它,否则只需释放它。


谢谢回答。我正在尝试理解检查播放器是否准备好的目的,如果错误涉及录制机的不正确停止。或者为什么我们使用MediaPlayer.OnPreparedListener而不是MediaRecorder.OnPreparedListener。实际上,后者似乎不存在。 - DataMeta
@DataMeta,您需要根据您的设置设置侦听器。如果您正在使用录音机,请使用MeidaRecorder;否则,请使用MediaPlayer。 - A Farmanbar
我想说的是,似乎MediaRecorder没有OnPreparedListener? - DataMeta
@DataMeta 很高兴为您服务。 - A Farmanbar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接