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

Expo-AV Playback类unloadAsync方法执行成功但抛出TypeError错误的解决方法咨询

解决Expo-AV Audio.Sound卸载时的TypeError: this._eventEmitter.removeSubscription is not a function错误

这个错误我之前排查过,大多是音频实例的内部状态异常导致的——要么是调用unloadAsync时实例已经被部分清理,要么是异步加载的流程没处理好,组件卸载时操作了无效的sound实例。结合你的代码,给你几个可行的解决方案:

1. 修正异步加载与清理的流程控制

你原代码用then回调赋值soundHandler,但组件可能在音频加载完成前就卸载,或者清理函数执行时实例状态不稳定。改成async/await并添加挂载状态检查,能有效规避这个问题:

import { Audio } from 'expo-av';
...
useEffect(() => {
  let soundHandler = null;
  let isMounted = true; // 标记组件是否仍挂载,防止异步操作后处理无效实例

  const loadSound = async () => {
    try {
      const { sound } = await Audio.Sound.createAsync(
        require('../assets/test.mp3'),
        { shouldPlay: true, isLooping: true }
      );
      if (isMounted) {
        soundHandler = sound;
      }
    } catch (err) {
      console.error('加载音频失败:', err);
    }
  };

  loadSound();

  return async () => {
    isMounted = false;
    if (soundHandler) {
      try {
        // 先暂停音频,确保实例处于稳定状态再卸载
        await soundHandler.pauseAsync();
        await soundHandler.unloadAsync();
      } catch (err) {
        console.log("卸载警告: " + err);
      } finally {
        soundHandler = null; // 清空引用,避免内存泄漏
      }
    }
  };
}, []);
...

改动的原因:

  • isMounted标志能防止组件卸载后,异步加载完成的回调再给soundHandler赋值,避免后续清理时操作无效实例。
  • 卸载前先暂停音频,确保实例内部状态稳定,减少事件订阅相关的异常。
  • 用async/await让异步流程更清晰,避免回调嵌套导致的状态不一致。

2. 更新Expo-AV到最新稳定版

这个错误在旧版本的Expo-AV中是已知问题,官方后续版本修复了事件订阅清理的逻辑。你可以运行以下命令更新到兼容版本:

expo install expo-av

3. 避免重复调用卸载操作

如果组件有多次挂载/卸载的场景,要确保不会对同一个sound实例重复调用unloadAsync——第一次卸载后实例已经失效,再次调用就会触发这个错误。上面代码中finally块清空soundHandler的操作就能避免这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 12:49:05