首页 > 解决方案 > 从 React Native Expo AV 中保存的 Uri 不起作用?

问题描述

我创建了一组包含音频数据的字典。用户必须录制这些音频,然后他们才能收听。问题是这些音频是用一个平面列表表示的,当我在它们之间传递时,它找不到 uri。例如:

const [data, setData] = useState(
    {uri: null, duration: 0},
    {uri: null, duration: 0},
    {uri: null, duration: 0}
)

const [index, setIndex] = useState()
const [step, setStep] = useState(0)
const [recording, setRecoding] = useState()
const [sound, setSound] = useState()
const [curDuration, setCurduration] = useState(0)
const [isBuffering, setIsBuferring] = useState(false)

const leftArrow = async () => {
    if (index >= 1) {
        flatlist.current.scrollToIndex({ animated: true, index: index - 1 })
        if (newAudio[index - 1].grabacion != null) {
            await sound.unloadAsync()
            loadAudio(index - 1)
        }
        setIndex(index - 1)
    };
}

const rightArrow = async () => {
    if (index < newAudio.length - 1) {
        flatlist.current.scrollToIndex({ animated: true, index: index + 1 })
        if (newAudio[index + 1].grabacion != null) {
            await sound.unloadAsync()
            loadAudio(index + 1)
        }
        setIndex(index + 1)
    }
}

const loadAudio = async (idx) => {
    const playbackInstance = new Audio.Sound()
    const source = { uri: newAudio[idx].grabacion }
    const status = { shouldPlay: isPlaying }

    playbackInstance.setOnPlaybackStatusUpdate((status) => { setIsBuffering(status.isBuffering) })
    await playbackInstance.loadAsync(source, status, false)
    setSound(playbackInstance)
}

const startRecording = async () => {
    try {
        setStep(1)
        console.log('Requesting permissions..');
        await Audio.requestPermissionsAsync();
        await Audio.setAudioModeAsync({
            allowsRecordingIOS: false,
            playsInSilentModeIOS: true,
            playThroughEarpieceAndroid: false,
            staysActiveInBackground: true,
            interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DUCK_OTHERS,
            shouldDuckAndroid: true,
            interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DUCK_OTHERS,
        });
        console.log('Starting recording..');
        const recording = new Audio.Recording();
        await recording.prepareToRecordAsync(Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY);
        await recording.startAsync();
        setRecording(recording);
        console.log('Recording started');
    } catch (err) {
        console.error('Failed to start recording', err);
    }
}

const stopRecording = async () => {
    console.log('Stopping recording..');
    setRecording(undefined);
    await recording.stopAndUnloadAsync();
    const uri = recording.getURI();
    // set the sound
    console.log('Loading Sound');
    const { sound } = await Audio.Sound.createAsync({ uri: uri });
    setSound(sound);
    //check the status
    let status = await sound.getStatusAsync()
    //save uri and duration
    updateValues( status.durationMillis, status.uri);
}

const updateValues = (dur, uri) => {
    data[index] = {
        duration: dur,
        grabacion: uri
    }
    setNewAudio(newAudio)
}

return (
    
    <View>
        <Flatlist
            data={data}
            horizontal={true}
            initialScrollIndex={index}
            pagingEnabled={true}
            scrollEnabled={false}
            initialScrollIndex={index}
            showsHorizontalScrollIndicator={false}
            keyExtractor={(item, index) => index.toString()}
            renderItem={(itemData) => {
                <View>

                    <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
                        <TouchableOpacity onPress={leftArrow}>
                            <AntDesign name='arrowleft'  />
                        </TouchableOpacity>
                        <TouchableOpacity onPress={rightArrow}>
                            <AntDesign name='arrowright' />
                        </TouchableOpacity>
                    </View>

                    {step == 0 ?
                        <TouchableOpacity onPress={startRecording()}>
                            <Fontisto name='mic' />
                        </TouchableOpacity >
                            : step == 1 ?
                            <TouchableOpacity onPress={stopRecording()}>
                                <MaterialIcons name='stop' />
                            </TouchableOpacity >
                                : <TouchableOpacity onPress={HanddlePlayStop()} >
                                    {isPlaying ?
                                        <Fontisto name='pause' />
                                        :
                                        <Fontisto name='play' />
                                    }
                                </TouchableOpacity >
                        }

                    <Slider
                        disabled={isPlaying ? true : false}
                        value={curDuration}
                        minimumValue={0}
                        maximumValue={itemData.item.duration}
                        onSlidingComplete={async (value) => {
                            await sound.setPositionAsync(value)
                        }}
                    />
                </View>

            }
        />
    </View>
    )

我得到的问题是,当我按 arrowRight() 或 arrowLeft() 并且我们要去的索引已经有记录时,它不能识别 uri。有人可以帮我吗

标签: react-nativeurireact-native-flatlistexpo-av

解决方案


我能够通过将 uri 保存在 UseState 中来解决它,并且在 updateValues 函数中,我将使用 uri 的 useState 变量而不是 status.uri 来更改值获取。由于某种原因 status.uri 没有正确保存 uri


推荐阅读