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

Expo-Video循环播放引发内存持续升高问题求助

Expo AV Video循环播放内存泄漏问题(SDK 48 / expo-av 13.2.1)

问题描述

在Expo托管的React Native项目中,使用expo-av的Video组件作为屏幕背景,10秒视频循环播放时,每次循环重启都会导致内存占用持续上升——即便视频仅2MB大小,内存仍会无限增长。相关代码如下:

const StyledVideo = styled(Video).attrs({
  isMuted: true,
  usePoster: true,
  isLooping: true,
  source: VIDEO_SRC, // require(<LOCAL_ASSET>)
  posterSource: STATIC_SRC, // require(<LOCAL_ASSET>)
  resizeMode: ResizeMode.STRETCH,
})`
  ${ratioCss};
`;

export const Background: FunctionComponent = () => {
  const [isVideoReady, setIsVideoReady] = useState<boolean>(false);

  const screenFocused = useIsFocused();
  const reduceMotion = useReducedMotionEnabled();

  return (
    <CenteringWrapper>
      <StyledVideo
        shouldPlay={screenFocused && !reduceMotion && isVideoReady}
        PosterComponent={({ source }) => <StaticBackground source={source} />}
        onReadyForDisplay={() => setIsVideoReady(true)}
      />
    </CenteringWrapper>
  );
};

当前环境:Expo SDK 48,expo-av 13.2.1

解决方案

1. 手动管理视频实例生命周期

组件卸载或屏幕失焦时,主动调用unloadAsync()释放资源,避免循环时残留未释放的视频实例:

export const Background: FunctionComponent = () => {
  const [isVideoReady, setIsVideoReady] = useState<boolean>(false);
  const videoRef = useRef<Video>(null);
  const screenFocused = useIsFocused();
  const reduceMotion = useReducedMotionEnabled();

  useEffect(() => {
    // 屏幕失焦时卸载视频,聚焦时重新加载
    if (!screenFocused) {
      videoRef.current?.unloadAsync();
      setIsVideoReady(false);
    } else if (!isVideoReady) {
      videoRef.current?.loadAsync(VIDEO_SRC);
    }

    // 组件卸载时清理资源
    return () => {
      videoRef.current?.unloadAsync();
    };
  }, [screenFocused, isVideoReady]);

  return (
    <CenteringWrapper>
      <StyledVideo
        ref={videoRef}
        shouldPlay={screenFocused && !reduceMotion && isVideoReady}
        PosterComponent={({ source }) => <StaticBackground source={source} />}
        onReadyForDisplay={() => setIsVideoReady(true)}
      />
    </CenteringWrapper>
  );
};

2. 替换自动循环为手动控制

关闭isLooping,通过播放结束事件手动重置播放位置,绕开组件内部可能的循环内存泄漏逻辑:

const StyledVideo = styled(Video).attrs({
  isMuted: true,
  usePoster: true,
  isLooping: false, // 关闭自动循环
  source: VIDEO_SRC,
  posterSource: STATIC_SRC,
  resizeMode: ResizeMode.STRETCH,
})`
  ${ratioCss};
`;

export const Background: FunctionComponent = () => {
  const [isVideoReady, setIsVideoReady] = useState<boolean>(false);
  const videoRef = useRef<Video>(null);
  const screenFocused = useIsFocused();
  const reduceMotion = useReducedMotionEnabled();

  const handlePlaybackStatus = async (status: PlaybackStatus) => {
    // 播放结束时重置到开头并继续播放
    if (status.didJustFinish && !status.isLooping) {
      await videoRef.current?.seekAsync(0);
      videoRef.current?.playAsync();
    }
  };

  useEffect(() => {
    return () => {
      videoRef.current?.unloadAsync();
    };
  }, []);

  return (
    <CenteringWrapper>
      <StyledVideo
        ref={videoRef}
        shouldPlay={screenFocused && !reduceMotion && isVideoReady}
        PosterComponent={({ source }) => <StaticBackground source={source} />}
        onReadyForDisplay={() => setIsVideoReady(true)}
        onPlaybackStatusUpdate={handlePlaybackStatus}
      />
    </CenteringWrapper>
  );
};

3. 调整expo-av版本

SDK 48对应的expo-av 13.2.1可能存在循环播放的内存泄漏bug,尝试升级到同SDK兼容的更高版本(如13.3.0),或降级到13.1.0,验证问题是否消失。

4. 优化视频编码

将视频转码为H.264编码的MP4格式,确保分辨率、帧率与设备屏幕匹配,减少解码过程中的内存消耗。

内容的提问来源于stack exchange,提问作者Zając

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 12:52:03