如何在Android音频录制应用中添加按钮按压延迟以修复录制问题
Hey there! Let's work through those two frustrating issues with your audio recording app together. I'll break down the root causes and walk you through a fix using the delayed button state approach you mentioned.
Fixing Your Audio Recording App Problems
Why These Issues Happen
First, let's unpack what's going wrong:
- Missing final audio segments: When you call
stopRecording()immediately after lifting your finger, theMediaRecorderoften hasn't finished writing the last bits of audio data to the file. Waiting 2 seconds gives it time to flush those final bytes, but that's not a great user experience. - App crashes on button touch: Your original
MediaPlayercode has a critical mistake—you first create a valid initialized instance withMediaPlayer.create(), then immediately overwrite it with a new, emptyMediaPlayer()object. This leads to null pointers or invalid state errors when you try to set the data source, causing crashes.
The Solution: Add a Post-Lift Delay
We'll use a Handler to add a short delay after the user lifts their finger. This gives the recorder time to finalize the audio file, and we'll fix the MediaPlayer logic to stop crashes. Here's the revised code:
Updated Touch Listener Code
// Define a Handler and reusable Runnable for delayed actions private Handler mRecordHandler = new Handler(); private Runnable mStopPlaybackRunnable; mRecordBtn.setOnTouchListener(new View.OnTouchListener(){ @Override public boolean onTouch(View view, MotionEvent motionEvent) { switch (motionEvent.getAction()) { case MotionEvent.ACTION_DOWN: // Cancel any pending delay if the user presses again early if (mStopPlaybackRunnable != null) { mRecordHandler.removeCallbacks(mStopPlaybackRunnable); } startRecording(); mRecordLabel.setText("Recording..."); break; case MotionEvent.ACTION_UP: mRecordLabel.setText("Finishing up..."); // Create the runnable that handles stopping and playback mStopPlaybackRunnable = new Runnable() { @Override public void run() { stopRecording(); mRecordLabel.setText("Recording Stopped..."); // Fixed MediaPlayer logic to avoid crashes MediaPlayer soundPlayer = null; try { soundPlayer = new MediaPlayer(); soundPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); soundPlayer.setDataSource(fileName); soundPlayer.prepare(); soundPlayer.start(); // Update label once playback begins mRecordLabel.setText("Do it again!"); // Release MediaPlayer after playback finishes to avoid leaks soundPlayer.setOnCompletionListener(mp -> mp.release()); } catch (IOException e) { e.printStackTrace(); mRecordLabel.setText("Playback failed!"); } } }; // Delay execution by 1.5 seconds (adjust this value as needed) mRecordHandler.postDelayed(mStopPlaybackRunnable, 1500); break; } return true; // Critical: Return true to ensure we receive all touch events } });
Key Changes Explained
- Delayed Stop/Playback: The
postDelayed()call gives theMediaRecorder1.5 seconds to write all remaining audio data to the file, eliminating the need for the user to wait for silence. - Fixed MediaPlayer: Removed the redundant
MediaPlayer.create()call that was being overwritten. Now we properly initialize oneMediaPlayerinstance, handle exceptions safely, and release it after playback to avoid memory leaks. - Touch Event Consumption: Changed
return falsetoreturn trueso the button receives all touch events consistently, preventing unexpected behavior. - Cancel Pending Actions: If the user presses the button again before the delay finishes, we cancel the previous runnable to avoid conflicting stop/playback operations.
Updated Recording/Stop Methods
Your core recording logic is solid, but we'll add safeguards to prevent crashes if the recorder fails to start:
private void startRecording() { recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); recorder.setOutputFile(fileName); // Ensure this is a unique path per recording! recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); try { recorder.prepare(); recorder.start(); } catch (IOException e) { Log.e(LOG_TAG, "prepare() failed: " + e.getMessage()); mRecordLabel.setText("Failed to start recording!"); } } private void stopRecording() { if (recorder != null) { try { recorder.stop(); } catch (RuntimeException e) { // Handle cases where the recorder didn't start properly Log.e(LOG_TAG, "stop() failed: " + e.getMessage()); } recorder.release(); recorder = null; } }
Testing Tips
- Adjust the delay time (1500ms) to your preference—1000ms (1 second) might work if 1.5 feels too long.
- Double-check that your app has the required permissions (
RECORD_AUDIO, and storage permissions if saving to external storage) declared in your manifest.
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

