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

如何复用Expo的Audio.Recording对象实现多次录音?

复用Audio.Recording实例优化语音录制体验

完全可以复用单个Audio.Recording实例,这正是解决你当前频繁录音场景下性能问题的最优方案。

当前方案的核心问题

每次长按都创建新实例并执行prepareToRecordAsync异步操作,这个过程涉及硬件资源初始化、编码配置加载,频繁触发会产生明显延迟,直接影响用户操作流畅感;而结束时调用stopAndUnloadAsync会彻底卸载录制资源,导致下次录音必须重复初始化流程。

复用实例的实现方案

只在组件初始化阶段创建一次Recording实例并完成准备工作,后续每次录音仅重置状态、启动/停止录制,无需重复初始化。

1. 一次性初始化实例

const recording = React.useRef<Audio.Recording | null>(null);

// 组件挂载时完成实例创建与准备
React.useEffect(() => {
  const initRecording = async () => {
    try {
      recording.current = new Audio.Recording();
      
      recording.current.setOnRecordingStatusUpdate((...args) => {
          // 你的状态更新逻辑(比如音量监测、时长统计)
      });

      recording.current.setProgressUpdateInterval(50);

      // 仅执行一次准备操作
      await recording.current.prepareToRecordAsync({
          isMeteringEnabled: true,
          android: {
              extension: '.mp3',
              outputFormat: AndroidOutputFormat.MPEG_4,
              audioEncoder: AndroidAudioEncoder.AAC,
              sampleRate: 44100,
              numberOfChannels: 2,
              bitRate: 128000,
          },
          ios: {
              extension: '.mp3',
              outputFormat: IOSOutputFormat.MPEG4AAC,
              audioQuality: IOSAudioQuality.MAX,
              sampleRate: 44100,
              numberOfChannels: 2,
              bitRate: 128000,
              linearPCMBitDepth: 16,
              linearPCMIsBigEndian: false,
              linearPCMIsFloat: false,
          },
          web: {
              mimeType: 'audio/webm',
              bitsPerSecond: 128000,
          },
      });
    } catch (err) {
      console.log('初始化录音实例失败', err);
      recording.current = null;
    }
  };

  initRecording();

  // 组件卸载时彻底清理资源
  return () => {
    if (recording.current) {
      recording.current.stopAndUnloadAsync().catch(err => console.log('清理录音实例失败', err));
      recording.current = null;
    }
  };
}, []);

2. 修改开始录音逻辑

const startRecording = React.useCallback(async () => {
  if (!recording.current) return;

  try {
    // 重置之前的录制数据,让实例回到可录制状态
    await recording.current.resetAsync();
    await recording.current.startAsync();
  } catch (err) {
    console.log('开始录音失败', err);
  }
}, []);

3. 修改停止录音逻辑

const stopRecording = React.useCallback(async () => {
  if (!recording.current) return;

  try {
    // 用stopAsync替代stopAndUnloadAsync,保留实例资源
    await recording.current.stopAsync();
    const uri = recording.current.getURI();
    console.log('录音文件URI', uri);
    
    // 若无需立即处理文件,可提前resetAsync为下次录音做准备
    // await recording.current.resetAsync();
  } catch (err) {
    console.log('停止录音失败', err);
  }
}, []);

关键注意事项

  • 核心差异:stopAsync仅停止录制,不会卸载底层资源;而stopAndUnloadAsync会彻底释放资源,导致实例无法复用
  • 重置状态:每次录音前调用resetAsync清除上次录制的缓存数据,避免数据污染
  • 内存管理:组件卸载时必须调用stopAndUnloadAsync并销毁实例,防止内存泄漏
  • 异常处理:所有异步操作都要加try-catch,并在调用方法前检查实例是否存在,避免空指针错误

内容的提问来源于stack exchange,提问作者Mike K

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 13:23:38