MediaRecorder.stop()抛出IllegalException,点击停止录制致应用崩溃
MediaRecorder录制异常后停止崩溃问题修复
问题根源
- 当
startRecording方法中prepare()或start()抛出异常时,mediaRecorder对象已被实例化但未进入合法录制状态,此时调用stop()会触发IllegalStateException,直接导致应用崩溃。 getOutputFilePath方法未确保目标目录存在,若AudioRecording文件夹不存在,会引发prepare()失败;且未处理directory为空的情况,会生成无效路径。- 异常发生后未及时清理
mediaRecorder实例,残留的无效对象会导致后续操作出错。
修复方案及代码调整
1. 异常时清理MediaRecorder
在startRecording的异常捕获块中,立即释放并置空mediaRecorder,避免后续停止操作触发错误。
2. 确保输出目录存在
在getOutputFilePath中检查并创建目标目录,同时处理directory为空的边界情况。
3. 安全停止录制
新增状态标记追踪录制状态,在stopRecording中增加异常捕获,避免非法状态下的操作引发崩溃。
修改后的完整代码:
private var mediaRecorder: MediaRecorder? = null // 新增状态标记,精准追踪录制状态 private var isRecording = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.sendIcon.setOnClickListener { startRecording() } binding.recordingIcon.setOnClickListener { stopRecording() } } private fun startRecording() { if (mediaRecorder == null && !isRecording) { mediaRecorder = MediaRecorder().apply { setAudioSource(MediaRecorder.AudioSource.MIC) setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP) setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB) setAudioSamplingRate(16000) setOutputFile(getOutputFilePath()) } try { mediaRecorder?.prepare() mediaRecorder?.start() isRecording = true } catch (e: Exception) { Log.d("TAG","Recording Exception " + e.localizedMessage) // 异常时立即清理资源 mediaRecorder?.release() mediaRecorder = null isRecording = false } } } private fun stopRecording() { if (mediaRecorder != null && isRecording) { try { mediaRecorder?.stop() } catch (e: IllegalStateException) { Log.d("TAG","Stop recording exception: " + e.localizedMessage) } finally { // 无论是否异常,都确保释放资源并重置状态 mediaRecorder?.release() mediaRecorder = null isRecording = false } } } private fun getOutputFilePath(): String { val recordingID = "Recording_" + System.currentTimeMillis() val directory = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){ applicationContext.getExternalFilesDir(Environment.DIRECTORY_MUSIC) } else { Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) } ?: run { // 处理存储目录为空的情况,降级使用应用内部存储 filesDir.also { it.mkdirs() } return it.absolutePath + "/AudioRecording/" + recordingID + ".3gp" } val targetDir = File(directory, "AudioRecording") // 创建目标目录,不存在则递归新建 if (!targetDir.exists()) { targetDir.mkdirs() } return File(targetDir, "$recordingID.3gp").absolutePath }
关键说明
isRecording状态标记避免了对未进入录制状态的MediaRecorder执行stop操作。- 异常捕获后立即清理资源,防止残留无效对象引发后续错误。
- 确保输出目录存在,同时兼容不同Android版本的存储策略,处理目录为空的边界场景。
stopRecording中的finally块保证无论是否出现异常,都能安全释放MediaRecorder资源。
内容的提问来源于stack exchange,提问作者Taki
相关产品推荐
相关产品推荐

