如何处理expo-av视频组件加载时的网络断开重连问题
解决思路
1. 监听网络状态,恢复时重新加载视频
使用expo-netinfo监听网络连接状态,当网络从断开恢复为连接时,调用视频实例的reloadAsync()方法重新加载视频资源。
先安装依赖(未安装时执行):
npx expo install expo-netinfo
修改后的组件代码:
import { NetInfo } from 'expo-netinfo'; import { Video, ResizeMode } from 'expo-av'; import { useEffect, useRef, useState } from 'react'; import { Dimensions } from 'react-native'; const { windowWidth, windowHeight } = Dimensions.get('window'); export default function VideoView(props: any) { const { question } = props; const videoRef = useRef(null); const [isConnected, setIsConnected] = useState(true); useEffect(() => { const unsubscribe = NetInfo.addEventListener(state => { const wasConnected = isConnected; setIsConnected(state.isConnected); // 网络从断开恢复时,触发视频重新加载 if (!wasConnected && state.isConnected && videoRef.current) { videoRef.current.reloadAsync(); } }); return () => unsubscribe(); }, [isConnected]); return ( <Video videoStyle={{ marginHorizontal: 10 }} source={{ uri: question.video_url }} rate={1.0} volume={1.0} isMuted={false} resizeMode={ResizeMode.CONTAIN} shouldPlay ref={videoRef} style={{ width: windowWidth, height: windowHeight }} /> ); }
2. 捕获视频加载错误,结合网络状态重试
通过Video组件的onError回调捕获网络类加载错误,记录错误状态,待网络恢复时触发重新加载。
代码示例:
import { NetInfo } from 'expo-netinfo'; import { Video, ResizeMode } from 'expo-av'; import { useEffect, useRef, useState } from 'react'; import { Dimensions } from 'react-native'; const { windowWidth, windowHeight } = Dimensions.get('window'); export default function VideoView(props: any) { const { question } = props; const videoRef = useRef(null); const [isConnected, setIsConnected] = useState(true); const [hasLoadError, setHasLoadError] = useState(false); useEffect(() => { const unsubscribe = NetInfo.addEventListener(state => { const wasConnected = isConnected; setIsConnected(state.isConnected); // 网络恢复且之前存在加载错误时,重新加载视频 if (!wasConnected && state.isConnected && hasLoadError && videoRef.current) { videoRef.current.reloadAsync(); setHasLoadError(false); } }); return () => unsubscribe(); }, [isConnected, hasLoadError]); const handleVideoError = (error) => { // 根据错误信息判断是否为网络相关错误 if (error.message.includes('network') || error.code === 'E_NETWORK') { setHasLoadError(true); } }; return ( <Video videoStyle={{ marginHorizontal: 10 }} source={{ uri: question.video_url }} rate={1.0} volume={1.0} isMuted={false} resizeMode={ResizeMode.CONTAIN} shouldPlay ref={videoRef} style={{ width: windowWidth, height: windowHeight }} onError={handleVideoError} /> ); }
3. 重置视频源触发重新加载
如果reloadAsync()不生效,可以将视频source存入state,网络恢复时重新设置source(添加时间戳避免缓存),触发组件重新渲染加载。
代码示例:
import { NetInfo } from 'expo-netinfo'; import { Video, ResizeMode } from 'expo-av'; import { useEffect, useRef, useState } from 'react'; import { Dimensions } from 'react-native'; const { windowWidth, windowHeight } = Dimensions.get('window'); export default function VideoView(props: any) { const { question } = props; const videoRef = useRef(null); const [isConnected, setIsConnected] = useState(true); const [videoSource, setVideoSource] = useState({ uri: question.video_url }); useEffect(() => { const unsubscribe = NetInfo.addEventListener(state => { const wasConnected = isConnected; setIsConnected(state.isConnected); if (!wasConnected && state.isConnected) { // 重置source并添加时间戳,避免缓存导致不重新加载 setVideoSource({ uri: `${question.video_url}?t=${Date.now()}` }); } }); return () => unsubscribe(); }, [isConnected, question.video_url]); return ( <Video videoStyle={{ marginHorizontal: 10 }} source={videoSource} rate={1.0} volume={1.0} isMuted={false} resizeMode={ResizeMode.CONTAIN} shouldPlay ref={videoRef} style={{ width: windowWidth, height: windowHeight }} /> ); }
内容的提问来源于stack exchange,提问作者X3R0
相关产品推荐
相关产品推荐

