我的 android 应用程序崩溃,触摸按钮无法正常工作

My android app crashes, touch button fails to work properly

我正在构建一个录制和播放音频的应用程序。我使用触摸按钮进行录制。长时间触摸可以成功录制音频,但是如果我点击按钮而不用手指按住按钮超过一秒钟,我的应用程序就会崩溃。

    mRecordBtn.setOnTouchListener(new View.OnTouchListener(){
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                startRecording();
                mRecordLabel.setText("Recording...");
            }
            else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
                stopRecording();
                mRecordLabel.setText("Recording stopped");
            }
            return false;
        }
    });

    private void startRecording() {
        recorder = new MediaRecorder();
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        recorder.setOutputFile(fileName);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

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

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

Logcat 长时间触摸时(无错误):

    D/ViewRootImpl@406d73a[MainActivity]: ViewPostIme pointer 0
    I/MediaRecorderJNI: setup
    I/MediaRecorderJNI: setAudioSource(1)
    I/MediaRecorderJNI: setAudioEncoder(3)
    I/MediaRecorderJNI: setOutputFile
    I/MediaRecorderJNI: prepare
    I/MediaRecorderJNI: start
    D/ViewRootImpl@406d73a[MainActivity]: ViewPostIme pointer 1
    I/MediaRecorderJNI: stop
    I/MediaRecorderJNI: release
    W/MediaRecorder: mediarecorder went away with unhandled events

Logcat 点击时:

    D/ViewRootImpl@d597feb[MainActivity]: ViewPostIme pointer 0
    I/MediaRecorderJNI: setup
    I/MediaRecorderJNI: setAudioSource(1)
    I/MediaRecorderJNI: setAudioEncoder(3)
    I/MediaRecorderJNI: setOutputFile
    I/MediaRecorderJNI: prepare
    I/MediaRecorderJNI: start
    D/ViewRootImpl@d597feb[MainActivity]: ViewPostIme pointer 1
    I/MediaRecorderJNI: stop
    E/MediaRecorder: stop failed: -1007
    E/InputEventReceiver: Exception dispatching input event.
    E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
    E/MessageQueue-JNI: java.lang.RuntimeException: stop failed.
        at android.media.MediaRecorder._stop(Native Method)
        at android.media.MediaRecorder.stop(MediaRecorder.java:1340)
        at tk.gandriks.gaaudiotransform.MainActivity.stopRecording(MainActivity.java:162)
        at tk.gandriks.gaaudiotransform.MainActivity.access0(MainActivity.java:34)
        at tk.gandriks.gaaudiotransform.MainActivity.onTouch(MainActivity.java:78)
        at android.view.View.dispatchTouchEvent(View.java:12536)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:601)
        at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1871)
        at android.app.Activity.dispatchTouchEvent(Activity.java:3384)
        at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
        at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:563)
        at android.view.View.dispatchPointerEvent(View.java:12788)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5670)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5465)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5114)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5171)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7736)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7676)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7637)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7847)
        at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:197)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:325)
        at android.os.Looper.loop(Looper.java:142)
        at android.app.ActivityThread.main(ActivityThread.java:6944)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
    D/AndroidRuntime: Shutting down VM
    E/AndroidRuntime: FATAL EXCEPTION: main
    Process: tk.gandriks.gaaudiotransform, PID: 20802
    java.lang.RuntimeException: stop failed.
        at android.media.MediaRecorder._stop(Native Method)
        at android.media.MediaRecorder.stop(MediaRecorder.java:1340)
        at tk.gandriks.gaaudiotransform.MainActivity.stopRecording(MainActivity.java:162)
        at tk.gandriks.gaaudiotransform.MainActivity.access0(MainActivity.java:34)
        at tk.gandriks.gaaudiotransform.MainActivity.onTouch(MainActivity.java:78)
        at android.view.View.dispatchTouchEvent(View.java:12536)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
        at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:601)
        at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1871)
        at android.app.Activity.dispatchTouchEvent(Activity.java:3384)
        at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
        at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:563)
        at android.view.View.dispatchPointerEvent(View.java:12788)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5670)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5465)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5114)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5171)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7736)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7676)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7637)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7847)
        at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:197)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:325)
        at android.os.Looper.loop(Looper.java:142)
        at android.app.ActivityThread.main(ActivityThread.java:6944)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
    I/zygote64: Do partial code cache collection, code=29KB, data=20KB
    After code cache collection, code=28KB, data=20KB
    Increasing code cache capacity to 128KB
    I/MediaRecorderJNI: finalize
    release
    Application terminated.

我知道停止录制过程时有问题,但我似乎无法自行修复...

prepare 需要一些时间来执行,所以当你试图停止记录器但你不确定它是否已经启动时,你可以有一个变量isStarted来检查或包围停下来试一试。

解决方案 1

 private void startRecording() {
    recorder = new MediaRecorder();
    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    recorder.setOutputFile(fileName);
    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

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

    recorder.start();
    isStarted = true;
}

private void stopRecording() {
  if(isStarted) {
    recorder.stop();
    recorder.release();
    recorder = null;
    isStarted = false;
  }
}

解决方案 2

private void stopRecording() {
  try {
      recorder.stop();
      recorder.release();
      recorder = null;
  } catch(Exception e) {}
}