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

MediaRecorder.prepare()调用失败抛出异常,求解决办法

解决MediaRecorder prepare()失败的问题

以下是针对你遇到的问题的具体修复步骤:

1. 修正错误的存储路径

你直接使用"/Internal storage/recorded/asdf.mp4"不符合Android存储访问规则,系统会拒绝该路径的访问请求。推荐使用应用专属外部存储目录(Android 10+无需额外写权限,且卸载应用时文件会被自动清理):

private fun startRecording(button: Button) {
    // 获取应用专属外部存储的音乐目录,若外部存储不可用则 fallback 到内部存储
    val outputDir = getExternalFilesDir(Environment.DIRECTORY_MUSIC) ?: filesDir
    val recordDir = File(outputDir, "recorded")
    
    // 确保目标目录存在,不存在则创建
    if (!recordDir.exists()) {
        recordDir.mkdirs()
    }
    
    val outputFile = File(recordDir, "asdf.mp4")
    
    recorder = MediaRecorder().apply {
        setAudioSource(MediaRecorder.AudioSource.MIC)
        setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
        setOutputFile(outputFile.absolutePath) // 使用合法的文件路径
        setAudioEncoder(MediaRecorder.AudioEncoder.AAC)

        try {
            prepare()
            start()
            button.text = "mic started"
        } catch (er: IllegalStateException) {
            button.text = "IllegalStateException"
            er.printStackTrace()
        } catch (e: IOException) {
            button.text = "prepare failed"
            Log.e(LOG_TAG, "media recorder prepare() failed", e) // 打印完整异常堆栈
        }
    }
}

2. 补充动态权限申请

Android 6.0(API 23)及以上版本,危险权限(如RECORD_AUDIO、WRITE_EXTERNAL_STORAGE)仅在Manifest中声明是不够的,必须在运行时主动申请:

第一步:确认Manifest权限

确保AndroidManifest.xml中已添加权限(适配Android 10+的存储规则):

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 仅Android 10及以下版本需要写外部存储权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />

第二步:实现动态权限申请逻辑

在你的Activity中添加权限检查和申请代码:

private val REQUEST_RECORD_PERMISSIONS = 1001
private val requiredPermissions = arrayOf(
    Manifest.permission.RECORD_AUDIO,
    Manifest.permission.WRITE_EXTERNAL_STORAGE
)

// 录音按钮点击事件绑定此方法,而非直接调用startRecording
fun onRecordButtonClick(button: Button) {
    val missingPermissions = requiredPermissions.filter {
        ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
    }
    
    if (missingPermissions.isNotEmpty()) {
        ActivityCompat.requestPermissions(
            this,
            missingPermissions.toTypedArray(),
            REQUEST_RECORD_PERMISSIONS
        )
    } else {
        startRecording(button)
    }
}

// 处理权限申请结果
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == REQUEST_RECORD_PERMISSIONS) {
        val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
        if (allGranted) {
            // 权限全部通过,启动录音(替换为你的按钮控件ID)
            startRecording(findViewById(R.id.your_record_button))
        } else {
            findViewById<Button>(R.id.your_record_button).text = "权限被拒绝,无法录音"
        }
    }
}

3. 确认MediaRecorder配置顺序

MediaRecorder的配置顺序必须严格遵循以下流程,否则会抛出IllegalStateException:
setAudioSource → setOutputFormat → setOutputFile → setAudioEncoder
你的当前代码顺序是正确的,后续修改代码时注意不要打乱该顺序。

4. 查看完整异常日志

在IOException的catch块中,将异常对象传入Log.e方法,打印完整的异常堆栈信息,可帮助你定位具体错误原因(比如目录创建失败、路径无效等):

catch (e: IOException) {
    button.text = "prepare failed"
    Log.e(LOG_TAG, "media recorder prepare() failed", e)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 21:53:13