uni-app中uni.createInnerAudioContext()的onCanplay监听失效

uni-app中uni.createInnerAudioContext()的onCanplay监听失效

开发环境 版本号 项目创建方式
Windows 21H1 HBuilderX

示例代码:

<recordingVoice :recordingVoiceShow.sync="recordingVoiceShow" :recordingUrl.sync="recordingUrl"></recordingVoice>  

<playVoice v-if="(this.recordingUrl == '')?false:true" class="recordingSoundsPath" playType="user" :path.sync="recordingUrl" :recordingTrans.sync="recordingTranslation"></playVoice>
    mounted() {  
        //录音开始监听  
        this.recorderManager.onStart(() => {  
            this.timer = setInterval(() => {  
                this.times++;  
            }, 1000);  
        });  
        //录音停止后将音频临时文件地址发给父组件  
        this.recorderManager.onStop(res => {  
            console.log(res);  
            clearInterval(this.timer);  
            //录音结束后将音频临时地址暴露出去  
            this.$emit('update:recordingUrl', res.tempFilePath);  
            this.$emit('update:recordingVoiceShow', false);  
        });  
    }
    watch: {  
        path: {  
            immediate: true,  
            handler: function(newVal) {  
                if (newVal) {  
                    console.log(newVal)  
                    this.voicePath = newVal;  
                    this.innerAudioContext.src = newVal;  
                    //音频时长  
                    this.innerAudioContext.onCanplay(() => {  
                        console.log(this.innerAudioContext.duration);  
                        this.allTime = 0;  
                        this.allTime = this.timeChange(this.innerAudioContext.duration.toFixed(0));  
                    });  
                }  
            }  
        }  
    },

操作步骤:

  1. 页面第一次加载默认显示recordingVoice组件,playVoice组件通过v-if隐藏。
  2. 此时用户录音,recordingVoiceres.tempFilePath传到父页面,recordingVoice通过v-if控制消失,playVoice组件出现,并通过监听res.tempFilePath的方式,将res.tempFilePath赋值给recordingVoice组件,this.innerAudioContext.src = newVal,此时onCanplay监听生效,得到音频时长。
  3. 用户删除playVoice组件,this.innerAudioContext.destroy();this.$emit('update:path', ''); playVoice组件消失,recordingVoice组件重现。此时再执行1,2两步骤,onCanplay监听失效,无法监听。

预期结果:

onCanplay监听可以一直正常生效

实际结果:

onCanplay监听在第二次无法正常生效

bug描述:

uni.createInnerAudioContext接口第二次读取uni.getRecorderManager接口onStop监听回调中的res.tempFilePath无法触发uni.createInnerAudioContext的onCanplay方法的问题,可以正常播放,但是无法通过onCanplay监听获取到音频文件的duration,onError也没有触发。

更多关于uni-app中uni.createInnerAudioContext()的onCanplay监听失效的实战教程也可以访问 https://www.itying.com/category-93-b0.html

5 回复

2023年了,这个问题还有

更多关于uni-app中uni.createInnerAudioContext()的onCanplay监听失效的实战教程也可以访问 https://www.itying.com/category-93-b0.html


有官方的人在吗?这不算bug?还是你们无法复现?给个回复啊

2025了还没解决

解决的方法就是换一个文件播放

根据你的描述,这是一个典型的 uni.createInnerAudioContext() 生命周期管理问题。问题核心在于音频上下文实例的重复使用和事件监听器的累积。

问题分析:

  1. 事件监听器重复绑定:在 watchhandler 中,每次 path 变化都会执行 this.innerAudioContext.onCanplay(...),导致同一个音频实例上绑定了多个 onCanplay 监听器。第一次触发后,后续监听器可能因内部状态问题失效。

  2. 实例销毁不彻底:虽然你调用了 this.innerAudioContext.destroy(),但 destroy() 主要释放原生资源,不会自动移除之前通过 .onCanplay() 添加的 JavaScript 事件监听器。

  3. 状态残留:音频实例在第一次加载后已进入 canplay 状态,当重新设置 src 时,可能因内部状态未完全重置,导致后续的 onCanplay 回调无法再次触发。

解决方案:

修改 playVoice 组件的代码逻辑,确保每次加载音频时都使用全新的监听方式:

// 在 data 中初始化
data() {
    return {
        innerAudioContext: null,
        // ...其他数据
    }
},

// 修改 watch 中的处理
watch: {
    path: {
        immediate: true,
        handler: function(newVal) {
            if (newVal) {
                console.log(newVal);
                this.voicePath = newVal;
                
                // 销毁旧的音频实例
                if (this.innerAudioContext) {
                    this.innerAudioContext.destroy();
                    this.innerAudioContext = null;
                }
                
                // 创建新的音频实例
                this.innerAudioContext = uni.createInnerAudioContext();
                this.innerAudioContext.src = newVal;
                
                // 重新绑定事件监听
                this.innerAudioContext.onCanplay(() => {
                    console.log(this.innerAudioContext.duration);
                    this.allTime = 0;
                    this.allTime = this.timeChange(this.innerAudioContext.duration.toFixed(0));
                });
                
                // 添加错误监听以便调试
                this.innerAudioContext.onError((res) => {
                    console.error('音频错误:', res);
                });
            }
        }
    }
},

// 在组件销毁时清理
beforeDestroy() {
    if (this.innerAudioContext) {
        this.innerAudioContext.destroy();
        this.innerAudioContext = null;
    }
}
回到顶部