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));
});
}
}
}
},
操作步骤:
- 页面第一次加载默认显示
recordingVoice组件,playVoice组件通过v-if隐藏。 - 此时用户录音,
recordingVoice将res.tempFilePath传到父页面,recordingVoice通过v-if控制消失,playVoice组件出现,并通过监听res.tempFilePath的方式,将res.tempFilePath赋值给recordingVoice组件,this.innerAudioContext.src = newVal,此时onCanplay监听生效,得到音频时长。 - 用户删除
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
2023年了,这个问题还有
更多关于uni-app中uni.createInnerAudioContext()的onCanplay监听失效的实战教程也可以访问 https://www.itying.com/category-93-b0.html
有官方的人在吗?这不算bug?还是你们无法复现?给个回复啊
2025了还没解决
解决的方法就是换一个文件播放
根据你的描述,这是一个典型的 uni.createInnerAudioContext() 生命周期管理问题。问题核心在于音频上下文实例的重复使用和事件监听器的累积。
问题分析:
-
事件监听器重复绑定:在
watch的handler中,每次path变化都会执行this.innerAudioContext.onCanplay(...),导致同一个音频实例上绑定了多个onCanplay监听器。第一次触发后,后续监听器可能因内部状态问题失效。 -
实例销毁不彻底:虽然你调用了
this.innerAudioContext.destroy(),但destroy()主要释放原生资源,不会自动移除之前通过.onCanplay()添加的 JavaScript 事件监听器。 -
状态残留:音频实例在第一次加载后已进入
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;
}
}

