解决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
相关产品推荐
相关产品推荐

