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

Android音频录制:MediaRecorder弃用构造函数及报错解决咨询

问题分析与解决方案

一、报错原因

带Context参数的MediaRecorder(Context)构造函数是**Android 12(API 31)**才新增的API,当应用运行在低于API31的设备上时,系统内置的MediaRecorder类不存在该方法,因此会抛出NoSuchMethodError。

二、非弃用的MediaRecorder初始化方式

需根据系统版本做兼容处理:API31及以上使用带Context的构造,低于API31的版本继续使用无参构造(虽在API31+标记为弃用,但低版本仍可正常运行)。

封装初始化方法

private fun createRecorder(context: Context): MediaRecorder {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        MediaRecorder(context)
    } else {
        // 用注解抑制API31+的弃用警告
        @Suppress("DEPRECATION")
        MediaRecorder()
    }
}

在startRecording()中替换原实例化代码:

recorder = createRecorder(this)

三、现有代码的优化点

  1. 完善异常处理
    原代码空catch块会隐藏调试信息,至少添加异常日志:
try {
    prepare()
} catch (e: IOException) {
    e.printStackTrace()
    Toast.makeText(this@MainActivity, "录制初始化失败", Toast.LENGTH_SHORT).show()
    return
}
  1. 修复SimpleDateFormat兼容性
    android.icu.text.SimpleDateFormat仅API24+可用,改用兼容全版本的java.text.SimpleDateFormat,同时修正格式字符串(月份用MM而非mm,避免和分钟混淆):
import java.text.SimpleDateFormat

// ...
val simpleDateFormat = SimpleDateFormat("yyyy.MM.dd.HH.mm.ss", Locale.getDefault())
val date: String = simpleDateFormat.format(Date())
  1. 优化权限请求逻辑
    用户拒绝权限后,引导其理解权限必要性,而非重复请求:
if (!permissionGranted) {
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission[0])) {
        Toast.makeText(this, "需要录音权限才能录制音频", Toast.LENGTH_SHORT).show()
    }
    ActivityCompat.requestPermissions(this, permission, REQUEST_CODE)
    return
}
  1. 释放MediaRecorder资源
    Activity销毁时释放资源,避免内存泄漏和系统资源占用:
override fun onDestroy() {
    super.onDestroy()
    if (::recorder.isInitialized) {
        runCatching {
            if (isRecording || isPaused) {
                recorder.stop()
            }
        }
        recorder.release()
    }
}

四、修改后的关键代码片段

// 替换原startRecording方法
@RequiresApi(Build.VERSION_CODES.S)
private fun startRecording() {
    if (!permissionGranted) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission[0])) {
            Toast.makeText(this, "需要录音权限才能录制音频", Toast.LENGTH_SHORT).show()
        }
        ActivityCompat.requestPermissions(this, permission, REQUEST_CODE)
        return
    }
    recorder = createRecorder(this)

    dirPath = "${externalCacheDir?.absolutePath}/"
    val simpleDateFormat = SimpleDateFormat("yyyy.MM.dd.HH.mm.ss", Locale.getDefault())
    val date: String = simpleDateFormat.format(Date())
    filename = "audio_record_$date"

    recorder.apply {
        setAudioSource(MediaRecorder.AudioSource.MIC)
        setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
        setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
        setOutputFile("$dirPath$filename.mp3")
        try {
            prepare()
            start()
        } catch (e: IOException) {
            e.printStackTrace()
            Toast.makeText(this@MainActivity, "录制初始化失败", Toast.LENGTH_SHORT).show()
            return
        }
    }
    btnRecord.setImageResource(R.drawable.ic_pause)
    isRecording = true
    isPaused = false
}

private fun createRecorder(context: Context): MediaRecorder {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        MediaRecorder(context)
    } else {
        @Suppress("DEPRECATION")
        MediaRecorder()
    }
}

override fun onDestroy() {
    super.onDestroy()
    if (::recorder.isInitialized) {
        runCatching {
            if (isRecording || isPaused) {
                recorder.stop()
            }
        }
        recorder.release()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 07:10:29