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

Android Studio Kotlin:录音播放按钮点击崩溃,无法播放音频文件

录音播放失败问题排查与修复

问题根源分析

从错误提示和代码来看,导致播放失败的核心问题有以下几点:

  • 文件路径无效:代码中拼接路径时出现了双斜杠//,Environment.getExternalStorageDirectory().absolutePath本身已以/结尾,直接拼接/recorded_audio.mp3会生成/storage/emulated//0/recorded_audio.mp3这种系统无法识别的路径。
  • 录制格式与文件名不匹配:点击录制时设置的输出格式是THREE_GPP,但文件名后缀用了.mp3,3GP格式的文件无法被MediaPlayer以MP3格式解析,直接导致文件损坏。
  • MediaRecorder重复初始化:初始化阶段创建了一个MediaRecorder实例,点击录制按钮时又重新new了一个,未处理旧实例可能引发资源冲突或录制逻辑异常。
  • 权限缺失:如果未申请录音权限(RECORD_AUDIO)和存储权限(Android 13及以下需WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE,Android 13+需READ_MEDIA_AUDIO),音频文件无法正常写入存储,播放时自然找不到文件。
  • MediaPlayer资源泄漏:每次点击播放都新建MediaPlayer实例,但未在播放完成后释放,既浪费资源也可能引发播放异常。

修复后的完整代码

val hintBar: TextView = findViewById(R.id.hint_bar)
// 用File构造方法避免路径拼接错误,统一格式为3GP匹配录制配置
val outputFile = File(Environment.getExternalStorageDirectory(), "recorded_audio.3gp")
val filePath = outputFile.absolutePath

recordingStatusTextView = findViewById(R.id.recording_status)
startRecordingButton = findViewById(R.id.start_recording)
stopRecordingButton = findViewById(R.id.stop_recording)

var mediaRecorder: MediaRecorder? = null
lateinit var mediaPlayer: MediaPlayer

startRecordingButton.setOnClickListener {
    mediaRecorder?.release() // 释放旧实例,避免资源泄漏
    mediaRecorder = MediaRecorder().apply {
        setAudioSource(MediaRecorder.AudioSource.MIC)
        setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
        setOutputFile(filePath)
        setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)

        try {
            prepare()
            start()
            recordingStatusTextView.text = "Recording..."
        } catch (e: IllegalStateException) {
            e.printStackTrace()
            recordingStatusTextView.text = "录制失败: ${e.message}"
        } catch (e: IOException) {
            e.printStackTrace()
            recordingStatusTextView.text = "录制失败: ${e.message}"
        }
        hintBar.visibility = View.VISIBLE
    }
}

stopRecordingButton.setOnClickListener {
    try {
        mediaRecorder?.stop()
        mediaRecorder?.release()
        mediaRecorder = null
        recordingStatusTextView.text = "Recording Stopped"
    } catch (e: IllegalStateException) {
        e.printStackTrace()
        recordingStatusTextView.text = "停止失败: ${e.message}"
    } catch (e: IOException) {
        e.printStackTrace()
        recordingStatusTextView.text = "停止失败: ${e.message}"
    }
    hintBar.visibility = View.GONE
}

val playButton = findViewById<Button>(R.id.play_button)
playButton.setOnClickListener {
    // 先释放之前的MediaPlayer实例,避免冲突
    if (::mediaPlayer.isInitialized && mediaPlayer.isPlaying) {
        mediaPlayer.stop()
        mediaPlayer.release()
    }
    mediaPlayer = MediaPlayer()
    try {
        mediaPlayer.setDataSource(filePath)
        mediaPlayer.prepare()
        mediaPlayer.start()
        // 监听播放完成,自动释放资源
        mediaPlayer.setOnCompletionListener {
            it.release()
        }
    } catch (e: IOException) {
        Toast.makeText(this, "无法播放音频文件: ${e.message}", Toast.LENGTH_SHORT).show()
        Log.e("MediaPlayer", e.toString())
    }
}

额外注意事项

  1. 权限申请:在AndroidManifest.xml中添加必要权限,并在运行时动态申请:
<!-- Android 12及以下 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<!-- Android 13+ -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
  1. MP3格式录制:如果需要录制MP3格式,需调整MediaRecorder配置为OutputFormat.MPEG_4搭配AudioEncoder.AAC,同时文件名后缀用.mp3。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 13:10:49