1. Android录音与播放功能基础入门第一次在Android上实现录音功能时我踩过一个典型的坑录制的音频文件总是损坏无法播放。后来发现是忘记调用MediaRecorder的prepare()方法就直接start()了。这个经历让我意识到看似简单的录音功能背后其实藏着不少技术细节。Android平台提供了两套主要的音频处理APIMediaRecorder/MediaPlayer和AudioRecord/AudioTrack。前者适合快速实现标准录音播放功能后者则提供更底层的PCM数据处理能力。我们今天要重点讨论的是更适合新手的MediaRecorder方案。录音功能的本质是将麦克风采集的模拟信号转换为数字音频文件。这个过程涉及三个关键环节音频采集通过麦克风硬件获取声波信号编码压缩将原始PCM数据转换为压缩格式如AAC文件存储将编码后的数据写入存储设备播放功能则是这个过程的逆向操作核心步骤包括文件读取从存储设备加载音频文件解码处理将压缩格式还原为PCM数据音频输出通过扬声器或耳机播放声音在开始编码前我们需要在AndroidManifest.xml中声明必要权限uses-permission android:nameandroid.permission.RECORD_AUDIO / uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE / uses-permission android:nameandroid.permission.READ_EXTERNAL_STORAGE /2. 录音功能完整实现指南2.1 MediaRecorder初始化配置创建录音功能时正确的参数配置顺序非常关键。我曾经因为调错方法顺序导致应用崩溃后来总结出这个标准流程mediaRecorder new MediaRecorder(); mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); mediaRecorder.setOutputFile(audioFilePath);这里有几个容易出错的点需要注意设置参数的顺序必须严格遵循音源→格式→编码器→输出文件输出文件路径要确保应用有写入权限不同Android版本支持的编码格式可能不同2.2 录音控制与异常处理实现开始/停止录音功能时完整的异常处理必不可少。这是我的实战代码private void startRecording() { try { mediaRecorder.prepare(); mediaRecorder.start(); isRecording true; } catch (IOException e) { Log.e(AudioRecord, prepare failed: e.getMessage()); releaseMediaRecorder(); } } private void stopRecording() { try { mediaRecorder.stop(); } catch (IllegalStateException e) { Log.e(AudioRecord, stop failed: e.getMessage()); } releaseMediaRecorder(); } private void releaseMediaRecorder() { if (mediaRecorder ! null) { mediaRecorder.release(); mediaRecorder null; } isRecording false; }特别提醒MediaRecorder的stop()方法在极端情况下可能抛出IllegalStateException比如在还没开始录音时就调用stop()。好的做法是像上面代码那样用try-catch包裹。3. 语音播放功能深度解析3.1 MediaPlayer状态机理解MediaPlayer有个复杂的状态机新手常因状态处理不当导致崩溃。这张表格总结了关键状态转换当前状态允许操作典型错误IdlesetDataSource()直接调用prepare()Preparedstart()重复prepare()Startedpause()/stop()修改数据源Stoppedprepare()直接start()正确的播放流程应该是mediaPlayer new MediaPlayer(); mediaPlayer.setDataSource(filePath); mediaPlayer.prepareAsync(); // 异步准备防止ANR mediaPlayer.setOnPreparedListener(mp - { mp.start(); });3.2 播放进度控制实战给播放器添加进度控制能显著提升用户体验。这是我常用的实现方案// 添加SeekBar进度监听 seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser mediaPlayer ! null) { mediaPlayer.seekTo(progress); } } // 其他方法省略... }); // 启动进度更新线程 new Thread(() - { while (mediaPlayer ! null mediaPlayer.isPlaying()) { runOnUiThread(() - { seekBar.setProgress(mediaPlayer.getCurrentPosition()); seekBar.setMax(mediaPlayer.getDuration()); }); SystemClock.sleep(200); } }).start();注意点seekTo()要在主线程调用记得在播放结束时停止更新线程处理用户拖动和自动更新的冲突4. 高级功能与性能优化4.1 录音质量参数调优不同的应用场景需要不同的录音质量配置。这是我整理的参数对照表场景采样率比特率编码格式文件大小(1分钟)语音备忘录8kHz12kbpsAMR_NB~90KB语音通话16kHz24kbpsAMR_WB~180KB音乐录制44.1kHz128kbpsAAC~960KB设置示例// 高质量音乐录制配置 mediaRecorder.setAudioSamplingRate(44100); mediaRecorder.setAudioEncodingBitRate(128000); mediaRecorder.setAudioChannels(2); // 立体声4.2 低延迟播放优化在实时语音场景中低延迟是关键。通过AudioTrack可以实现更底层的控制AudioTrack track new AudioTrack( new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) .build(), new AudioFormat.Builder() .setEncoding(AudioFormat.ENCODING_PCM_16BIT) .setSampleRate(16000) .setChannelMask(AudioFormat.CHANNEL_OUT_MONO) .build(), bufferSize, AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE ); track.play(); // 写入PCM数据 track.write(audioData, offset, length);关键优化点使用VOICE_COMMUNICATION usage选择合适的缓冲区大小考虑使用MODE_STATIC减少延迟4.3 内存泄漏预防方案在音频处理中资源泄漏是常见问题。我总结了这个生命周期管理模板Override protected void onPause() { super.onPause(); releaseMediaPlayer(); // 释放播放器 releaseMediaRecorder(); // 释放录音器 } Override protected void onDestroy() { super.onDestroy(); handler.removeCallbacksAndMessages(null); // 清理Handler if (audioThread ! null) { audioThread.interrupt(); // 停止音频线程 } }特别要注意MediaPlayer的异步回调可能持有Activity引用应该在销毁时取消所有回调。