How to fix the error Suspension functions can be called only within coroutine body when I invoke a suspend fun in setOnInfoListener?

huangapple go评论63阅读模式
英文:

How to fix the error Suspension functions can be called only within coroutine body when I invoke a suspend fun in setOnInfoListener?

问题

以下是代码的翻译部分:

以下代码用于在Android Studio项目中记录声音并将项目保存到数据库中,使用了Room。当达到设置的最大持续时间并且已经达到时,系统将自动停止记录并将项目保存到数据库中。

但是,代码收到了以下错误信息:

“只能在协程体内调用悬挂函数”

我应该如何修复它?

override suspend fun startRecord(updateElapsedTime: UpdateElapsedTime) {
    
    with(mRecorder) {
        setAudioSource(MediaRecorder.AudioSource.MIC);
        setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        setMaxDuration(1000 * 60 * recordMaxValue);   
        setOutputFile(filename);

        setOnInfoListener { mr, what, extra ->
            if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {                   
                completeRecord(updateElapsedTime)     //它导致错误
            }
        }

        prepare()
        start()
    }

}


override suspend fun completeRecord(updateElapsedTime: UpdateElapsedTime) {
    try {          
        mRecorder.stop()

    } catch (e: Exception) {
    }
    saveRecord()
}

private suspend fun saveRecord() {
    val mInfo = MInfo()
    handleMInfo.add(mInfo)
}
英文:

The following code is to record a sound and save an item to database in Android Studio project with Room, and system will stop record and save item to database automatically when a maximum duration had been setup and has now been reached.

But the code receives the error information:

Suspension functions can be called only within coroutine body

How can I fix it?

override suspend fun startRecord(updateElapsedTime: UpdateElapsedTime) {

        with(mRecorder) {
            setAudioSource(MediaRecorder.AudioSource.MIC);
            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
            setMaxDuration(1000 * 60 * recordMaxValue);   
            setOutputFile(filename);

            setOnInfoListener { mr, what, extra ->
                if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {                   
                    completeRecord(updateElapsedTime)     //It causes error
                }
            }

            prepare()
            start()
        }

    }


    override suspend fun completeRecord(updateElapsedTime: UpdateElapsedTime) {
        try {          
            mRecorder.stop()

        } catch (e: Exception) {
        }
        saveRecord()
    }

    private suspend fun saveRecord() {
        val mInfo = MInfo()
        handleMInfo.add(mInfo)
    }

答案1

得分: 2

你传递给 setOnInfoListener 的这个 lambda 表达式并不在你的协程内调用。它会在监听器所在类期望的任何线程上被调用。

(对于 MediaRecorder,它会在用于实例化 MediaRecorder 的任何线程上被调用,除非那不是一个 LooperThread,在这种情况下它会在主线程上调用。)

由于监听器代码不在你的协程内调用,你不能在其中调用挂起函数。你必须在监听器中启动一个新的协程来调用挂起函数。如果你想避免泄漏 MediaRecorder,你必须使用适用于你的 MediaRecorder 生命周期的 CoroutineScope。

英文:

This lambda you pass to setOnInfoListener is not called inside your coroutine. It's called on whatever thread the listener's class wants to.

(In the case of MediaRecorder, it will be called on whatever thread was used to instantiate the MediaRecorder, unless that wasn't a LooperThread, in which case it will call it on the main thread.)

Since the listener code is not called in your coroutine, you cannot call suspend functions in it. You must launch a new coroutine in the listener to call a suspend function. You must use a CoroutineScope that is appropriate for the lifetime of your MediaRecorder if you want to avoid leaking the MediaRecorder.

huangapple
  • 本文由 发表于 2023年5月6日 15:28:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76187647.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定