查看Expo Audio.Recording
API,我没有看到任何"reset/empty/clean"内置方法,以重用传统对象或重置的方式重用.
该类表示一段录音.创建此类的实例后,必须调用prepareToRecordAsync
才能录制音频.录音完成后,请拨打stopAndUnloadAsync
.请注意,在任何给定时间,在prepareToRecordAsync
和stopAndUnloadAsync
之间的状态下只允许存在一个记录器.
一旦使用stopAndUnloadAsync
停止和卸载记录,Audio.Recording
对象就不能再用于新的记录会话.您必须 for each 新的录制会话实例化一个新的Audio.Recording
对象.
User Interaction App Logic Expo Audio API
│ │ │
├──── Press Record ──────> │
│ │ │
│ ├─── new Audio.Recording() ────>
│ │ │
│ ├─ prepareToRecordAsync() ─────>
│ │ │
│ ├─────── startAsync() ─────────>
│ │ │
│ │<──── Recording Starts ───────┤
│ │ │
│<────── UX Update ──────┤ │
虽然您无法在Expo应用程序中"清空"并直接重用Audio.Recording
个对象,但通过有效管理录制会话的生命周期,并在录制准备和清理阶段提供清晰的用户体验,您可以获得流畅高效的用户体验.
例如,您可以在准备录制时显示一个加载指示器或短暂禁用录制按钮,向用户发出正在发生的信号.
在记录停止、卸载并检索URI后,请确保通过将记录对象设置为null
来正确处理记录对象的清理(用于内存管理和避免潜在的泄漏).
const stopRecording = React.useCallback(async () => {
if (recording.current) {
await recording.current.stopAndUnloadAsync();
const uri = recording.current.getURI();
console.log('uri', uri);
// Cleanup after retrieving URI
recording.current = null;
}
}, []);
您还可以考虑使用React的useState
或useReducer
来管理录制状态,这可以提供一种更简化的方式来处理录制的生命周期状态(例如,空闲、录制、完成).
import React, { useState, useCallback } from 'react';
import { Audio } from 'expo-av';
// define state hooks for managing the recording state and the `Audio.Recording` objects
const MyRecorderComponent = () => {
const [recording, setRecording] = useState<Audio.Recording | null>(null);
const [recordState, setRecordState] = useState<'idle' | 'recording' | 'finished'>('idle');
};
const startRecording = useCallback(async () => {
try {
const newRecording = new Audio.Recording();
await newRecording.prepareToRecordAsync(Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY);
await newRecording.startAsync();
// Update state to reflect that recording has started
setRecording(newRecording);
setRecordState('recording');
} catch (err) {
console.error('Failed to start recording', err);
}
}, []);
const stopRecording = useCallback(async () => {
if (recording) {
await recording.stopAndUnloadAsync();
const uri = recording.getURI();
console.log('Recording stopped and stored at', uri);
// Reset state
setRecording(null);
setRecordState('finished');
}
}, [recording]);
在组件中使用recordState
来控制UI,根据应用程序是空闲、录制还是录制完成,显示不同的选项:
return (
<div>
{recordState === 'idle' && <button onClick={startRecording}>Start Recording</button>}
{recordState === 'recording' && <button onClick={stopRecording}>Stop Recording</button>}
{recordState === 'finished' && <p>Recording finished. Ready to record another.</p>}
</div>
);
我正在制作一个类似于WhatsApp的录音功能.这意味着我不可能每次都调用await newRecording.prepareToRecordAsync
.
然后,另一种方法是提前准备好记录对象,并重新使用它,最大限度地减少开始新记录时的延迟.如上所述,由于Expo API的约束,直接重用Audio.Recording
对象是不可能的.因此,您需要简化录制过程以尽可能响应:这意味着尽可能多地预加载,并减少录制开始/停止阶段执行的操作.
当您的组件被装入时,或在应用流程中的某个关键点,请提前准备一个Audio.Recording
对象.这样,当用户启动录制时,录制可以更快地开始.
在停止录制和准备下一个录制之间实现最小的延迟,以便应用程序始终为下一个用户操作做好准备.
使用React的useEffect
来处理准备和清理,确保录制在需要时准备好,并且资源被适当释放.
import React, { useEffect, useState, useCallback } from 'react';
import { Audio } from 'expo-av';
const MyRecorderComponent = () => {
const [recording, setRecording] = useState<Audio.Recording | null>(null);
const [isReady, setIsReady] = useState(false);
// Prepare the recording in advance
useEffect(() => {
const prepareRecording = async () => {
const newRecording = new Audio.Recording();
await newRecording.prepareToRecordAsync(Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY);
setRecording(newRecording);
setIsReady(true);
};
prepareRecording();
// Cleanup function to unload the recording when component unmounts
return () => {
if (recording) {
recording.stopAndUnloadAsync();
}
};
}, [recording]);
const startRecording = useCallback(async () => {
if (isReady && recording) {
await recording.startAsync();
// Other logic to handle recording start
}
}, [isReady, recording]);
const stopRecording = useCallback(async () => {
if (recording) {
await recording.stopAndUnloadAsync();
// Logic to handle after recording is stopped
// Optionally, prepare the next recording immediately after stopping
setIsReady(false);
const newRecording = new Audio.Recording();
await newRecording.prepareToRecordAsync(Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY);
setRecording(newRecording);
setIsReady(true);
}
}, [recording]);
return (
<div>
{isReady && <button onClick={startRecording}>Start Recording</button>}
{!isReady && <p>Preparing...</p>}
{/* Additional UI for stopping recording and handling the recorded data */}
</div>
);
};
这将提前准备一个Audio.Recording
个对象,并在录制停止后立即重新准备一个新的对象,让应用程序为下一次录制做好准备:在录制停止后立即这样做,而不是在新的录制开始前这样做,应该会增强应用程序的感知响应性.