react native - EXPO-Video freez - Stack Overflow

admin2025-04-16  4

Hi I'm encountering the problem where when i go from my app to other app, and go back not all the time but sometimes, it freezes and also it shows on the screen the icon that the video is not working, the funny thing is that i don't see any error or anything so, what should i do? Anyone with the same problem? I'm using latest expo-video, expo 52 and using flashlist. enter image description here

// video-players.state.ts

import { create } from 'zustand';
import { createVideoPlayer, VideoPlayer } from 'expo-video';

interface VideoPlayerEntry {
    player: VideoPlayer;
    source: string;
}

interface VideoPlayerMap extends Map<number, VideoPlayerEntry> {}

interface VideoPlayersState {
    videoPlayers: VideoPlayerMap;
    lastPlayed: number | null;
    initializePlayer: (index: number, videoSource: string) => void;
    getVideoData: (index: number) => VideoPlayerEntry | undefined;
    pauseAllVideos: () => void;
    releasePlayer: (index: number) => void;
    releaseAllPlayers: () => void;
    logAllPlayers: () => void;
    handleViewableItemsChanged: ({
        viewableItems,
    }: {
        viewableItems: Array<{ index: number | null }>;
    }) => void;
    setLastPlayed: (index: number) => void;
}

export const useVideoPlayersStore = create<VideoPlayersState>((set, get) => ({
    videoPlayers: new Map(),
    lastPlayed: null,

    initializePlayer: (index: number, videoSource: string) => {
        const videoPlayers = get().videoPlayers;
        if (!videoPlayers.has(index)) {
            const player = createVideoPlayer(videoSource);
            player.loop = true;
            player.generateThumbnailsAsync(1);
            videoPlayers.set(index, { player, source: videoSource });
            set({ videoPlayers: new Map(videoPlayers) });
        }
    },

    getVideoData: (index: number) => {
        return get().videoPlayers.get(index);
    },

    pauseAllVideos: () => {
        const videoPlayers = get().videoPlayers;
        videoPlayers.forEach((entry, index) => {
            if (entry.player.playing) {
                entry.player.pause();
                set({ lastPlayed: index });
            }
        });
    },

    releasePlayer: (index: number) => {
        const videoPlayers = get().videoPlayers;
        const entry = videoPlayers.get(index);
        if (entry) {
            if (entry.player.playing) {
                entry.player.pause();
            }
            entry.player.release();
            videoPlayers.delete(index);
            set({ videoPlayers: new Map(videoPlayers), lastPlayed: null });
        }
    },

    releaseAllPlayers: () => {
        const videoPlayers = get().videoPlayers;
        videoPlayers.forEach((entry) => {
            if (entry.player.playing) {
                entry.player.pause();
            }
            entry.player.release();
        });
        videoPlayers.clear();
        set({ videoPlayers: new Map(), lastPlayed: null });
    },

    logAllPlayers: () => {
        console.log('Logging players:');
        get().videoPlayers.forEach((entry, index) => {
            console.log(
                `Player at index ${index}: ${entry.player.playing ? 'Playing' : 'Paused'}, Source: ${entry.source}`,
            );
        });
    },

    handleViewableItemsChanged: ({ viewableItems }) => {
        const videoPlayers = get().videoPlayers;
        const visibleIndices = viewableItems
            .map((item) => item.index)
            .filter((i): i is number => i !== null);

        let played = false;
        videoPlayers.forEach((entry, index) => {
            if (visibleIndices.includes(index) && !played) {
                if (entry.player) {
                    entry.player.play();
                    played = true;
                }
            } else {
                if (entry.player.playing) {
                    entry.player.pause();
                }
            }
        });
    },

    setLastPlayed: (index: number) => {
        set({ lastPlayed: index });
    },
}));

Hi I'm encountering the problem where when i go from my app to other app, and go back not all the time but sometimes, it freezes and also it shows on the screen the icon that the video is not working, the funny thing is that i don't see any error or anything so, what should i do? Anyone with the same problem? I'm using latest expo-video, expo 52 and using flashlist. enter image description here

// video-players.state.ts

import { create } from 'zustand';
import { createVideoPlayer, VideoPlayer } from 'expo-video';

interface VideoPlayerEntry {
    player: VideoPlayer;
    source: string;
}

interface VideoPlayerMap extends Map<number, VideoPlayerEntry> {}

interface VideoPlayersState {
    videoPlayers: VideoPlayerMap;
    lastPlayed: number | null;
    initializePlayer: (index: number, videoSource: string) => void;
    getVideoData: (index: number) => VideoPlayerEntry | undefined;
    pauseAllVideos: () => void;
    releasePlayer: (index: number) => void;
    releaseAllPlayers: () => void;
    logAllPlayers: () => void;
    handleViewableItemsChanged: ({
        viewableItems,
    }: {
        viewableItems: Array<{ index: number | null }>;
    }) => void;
    setLastPlayed: (index: number) => void;
}

export const useVideoPlayersStore = create<VideoPlayersState>((set, get) => ({
    videoPlayers: new Map(),
    lastPlayed: null,

    initializePlayer: (index: number, videoSource: string) => {
        const videoPlayers = get().videoPlayers;
        if (!videoPlayers.has(index)) {
            const player = createVideoPlayer(videoSource);
            player.loop = true;
            player.generateThumbnailsAsync(1);
            videoPlayers.set(index, { player, source: videoSource });
            set({ videoPlayers: new Map(videoPlayers) });
        }
    },

    getVideoData: (index: number) => {
        return get().videoPlayers.get(index);
    },

    pauseAllVideos: () => {
        const videoPlayers = get().videoPlayers;
        videoPlayers.forEach((entry, index) => {
            if (entry.player.playing) {
                entry.player.pause();
                set({ lastPlayed: index });
            }
        });
    },

    releasePlayer: (index: number) => {
        const videoPlayers = get().videoPlayers;
        const entry = videoPlayers.get(index);
        if (entry) {
            if (entry.player.playing) {
                entry.player.pause();
            }
            entry.player.release();
            videoPlayers.delete(index);
            set({ videoPlayers: new Map(videoPlayers), lastPlayed: null });
        }
    },

    releaseAllPlayers: () => {
        const videoPlayers = get().videoPlayers;
        videoPlayers.forEach((entry) => {
            if (entry.player.playing) {
                entry.player.pause();
            }
            entry.player.release();
        });
        videoPlayers.clear();
        set({ videoPlayers: new Map(), lastPlayed: null });
    },

    logAllPlayers: () => {
        console.log('Logging players:');
        get().videoPlayers.forEach((entry, index) => {
            console.log(
                `Player at index ${index}: ${entry.player.playing ? 'Playing' : 'Paused'}, Source: ${entry.source}`,
            );
        });
    },

    handleViewableItemsChanged: ({ viewableItems }) => {
        const videoPlayers = get().videoPlayers;
        const visibleIndices = viewableItems
            .map((item) => item.index)
            .filter((i): i is number => i !== null);

        let played = false;
        videoPlayers.forEach((entry, index) => {
            if (visibleIndices.includes(index) && !played) {
                if (entry.player) {
                    entry.player.play();
                    played = true;
                }
            } else {
                if (entry.player.playing) {
                    entry.player.pause();
                }
            }
        });
    },

    setLastPlayed: (index: number) => {
        set({ lastPlayed: index });
    },
}));

Share Improve this question asked Feb 3 at 13:33 Filip ČorbaFilip Čorba 133 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 0

i've had the same issue. Tried a bunch of things and the only thing that helped is switching to expo-av.

Its not maintained anymore but it works for now. We should definitely raise this issue on expo github

I was also facing a similar issue with my looped videos. With expo-video you have a couple options:

option 1:

  • Set staysactiveinbackground = true, https://docs.expo.dev/versions/latest/sdk/video/#staysactiveinbackground
  • It just means it will continue to play even in the background.
  • The issue is that expo-video pauses the video upon entering background, which is not bad unless your supporting background audio and pip.

option 2

  • Listen to AppState and when entering forground, start you video again.

      import { AppState } from "react-native";
    
      useEffect(AppState.addEventListener('change', (nextAppState) => {
          switch(nextAppState) {
              case 'active':
                  // Video loop
                  player.play() 
                  break
              default:
                  break
          }
      }).remove, [video.playbackTimerSyncedWithVideo])
    
转载请注明原文地址:http://anycun.com/QandA/1744768949a87358.html