使用expo-audio录制音频时实例未释放导致重复获取旧音频的问题
expo-audio录制音频时实例未释放导致重复获取旧音频的问题
兄弟,我前阵子迁移expo音频库的时候也踩过这个坑!你的问题核心在于useAudioRecorder创建的实例默认会复用同一个临时文件路径,而且单纯调用stop()并不会自动清理或重置这个路径,导致每次新录制的音频都覆盖(或者直接复用)了旧文件,自然拿到的都是第一次的内容。
给你两个实用的解决方案,亲测有效:
方案一:手动指定唯一的输出文件路径(推荐)
我们可以借助expo-file-system生成每次录制的唯一临时路径,强制让录制器写入新文件,彻底避免复用旧资源。
先修改你的hook代码:
import { RecordingPresets, useAudioRecorder } from 'expo-audio'; import { useState } from "react"; import * as FileSystem from 'expo-file-system'; export default function useRecorder() { const audioRecorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY); const [isRecording, setIsRecording] = useState(false); const [recordedUri, setRecordedUri] = useState(null); // 用来存每次的录制结果 const startRecording = async () => { // 用时间戳生成唯一的文件名,保证路径不重复 const newRecordingUri = `${FileSystem.cacheDirectory}voice_recording_${Date.now()}.m4a`; // 传入新的输出路径重新准备录制 await audioRecorder.prepareToRecordAsync({ ...RecordingPresets.HIGH_QUALITY, outputUri: newRecordingUri }); audioRecorder.record(); setIsRecording(true); }; const stopRecording = async () => { await audioRecorder.stop(); // 保存本次录制的URI setRecordedUri(audioRecorder.uri); console.log("本次录制完成,文件URI:", audioRecorder.uri); setIsRecording(false); // 可选:重置录制器状态,释放内部资源 await audioRecorder.reset(); }; return { startRecording, stopRecording, recordedUri, isRecording }; }
这个方法的好处是完全可控,每次录制都用全新的文件,而且reset()方法能帮你清理录制器的内部状态,避免残留旧数据。
方案二:强制重新创建录制器实例
如果上面的方法还没解决问题,我们可以通过改变useAudioRecorder的key参数,让它每次停止录制后都销毁旧实例、创建新实例,从根源上避免旧资源的复用:
import { RecordingPresets, useAudioRecorder } from 'expo-audio'; import { useState } from "react"; export default function useRecorder() { // 用一个key来控制录制器实例的重建 const [recorderKey, setRecorderKey] = useState(0); const audioRecorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY, { key: recorderKey }); const [isRecording, setIsRecording] = useState(false); const [recordedUri, setRecordedUri] = useState(null); const startRecording = async () => { await audioRecorder.prepareToRecordAsync(); audioRecorder.record(); setIsRecording(true); }; const stopRecording = async () => { await audioRecorder.stop(); setRecordedUri(audioRecorder.uri); console.log("本次录制完成,文件URI:", audioRecorder.uri); setIsRecording(false); // 更新key,触发录制器实例重建 setRecorderKey(prevKey => prevKey + 1); }; return { startRecording, stopRecording, recordedUri, isRecording }; }
额外提醒
- 记得确保已经获取了
RECORD_AUDIO和WRITE_EXTERNAL_STORAGE(如果需要持久化保存)的权限,你提到省略了这部分,一定要确认权限没问题 - 缓存目录的文件可能会被系统自动清理,如果需要长期保存录制的音频,记得用
FileSystem.moveAsync()把文件移到持久化存储目录
内容来源于stack exchange
相关产品推荐
相关产品推荐

