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

解决setOnInfoListener中调用挂起函数的Suspension functions错误

解决「Suspension functions can be called only within coroutine body」错误

错误根源

MediaRecorder的OnInfoListener是普通的系统回调,运行在主线程但不属于任何协程作用域。而completeRecord是挂起函数,必须在协程体内调用,直接在回调里调用就会触发这个报错。

具体解决办法

在回调内部启动协程来调用挂起函数,根据你的组件类型选择对应的CoroutineScope:

1. ViewModel中使用

ViewModel自带viewModelScope,直接用它启动协程:

setOnInfoListener { mr, what, extra ->
    if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {                   
        viewModelScope.launch {
            completeRecord(updateElapsedTime)
        }
    }
}

2. Activity/Fragment中使用

用lifecycleScope(需依赖AndroidX的lifecycle-runtime-ktx库):

setOnInfoListener { mr, what, extra ->
    if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {                   
        lifecycleScope.launch {
            completeRecord(updateElapsedTime)
        }
    }
}

3. 自定义CoroutineScope(通用场景)

如果上述两种Scope都不适用,自己创建Scope,注意组件销毁时取消协程避免内存泄漏:

// 在类中初始化自定义Scope
private val recordScope = CoroutineScope(Dispatchers.Main + Job())

// 回调中启动协程
setOnInfoListener { mr, what, extra ->
    if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {                   
        recordScope.launch {
            completeRecord(updateElapsedTime)
        }
    }
}

// 组件销毁时取消Scope,比如Activity的onDestroy
override fun onDestroy() {
    super.onDestroy()
    recordScope.cancel()
}

额外提示

  • 要是saveRecord里有Room数据库操作,Room的DAO挂起函数会自动切换到后台线程,不用额外指定Dispatchers.IO;如果有其他耗时操作,可在saveRecord里用withContext(Dispatchers.IO)包裹。
  • 处理mRecorder.stop()时,尽量完善异常捕获,避免录制未正常启动导致的崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 23:03:23