Skip to content

🐛 Camera fails to initialize after process death. #3698

@soportetb

Description

@soportetb

What's happening?

When the app is in the background (minimized) and the device is turned off, then turned back on, and the app is reopened from the recent apps list, the camera fails to initialize. The camera preview shows no video feed, and the useCameraDevice("back") hook appears to return null or a stale device reference.

Steps to Reproduce
Open the app and navigate to any screen that uses the camera
Minimize the app (send to background)
Turn off the device completely
Turn the device back on
Open the app from the "recent apps" list (not a fresh launch)
Navigate to the camera screen

Actual Behavior
The camera shows a loading state indefinitely ("Cargando cámara...")
After 5 seconds, an alert appears offering to retry
Pressing "Retry" does not fix the issue - the camera still fails to initialize
The only workaround is to completely kill the app (swipe from recents) and launch it fresh

Enviroment:
expo: 53.0.0
react-native-vision-camera": 4.7.3
react-native: 0.79.6

This appears to be related to Android's behavior when terminating a process. When the device shuts down with the app running in the background, Android terminates the app's process. When reopened from recent apps, Android recreates the activity. However, when attempting to use the camera component again, the camera doesn't display an image.

Is there anything in the component's lifecycle that you're not handling well or should take into account?

THANKS!!

Reproduceable Code

React, { useState, useRef, useEffect } from "react";
import {
  View,
  TouchableOpacity,
  Text,
  StyleSheet,
  Alert,
  ActivityIndicator,
  AppState,
} from "react-native";
import {
  Camera,
  useCameraDevice,
  useCameraPermission,
} from "react-native-vision-camera";
import { useIsFocused } from "@react-navigation/native";

const CameraScreen = ({ navigation, route }) => {
  const { hasPermission } = useCameraPermission();
  const device = useCameraDevice("back");
  const [previewImage, setPreviewImage] = useState(null);
  const [cameraReady, setCameraReady] = useState(false);
  const [isCapturing, setIsCapturing] = useState(false);
  const cameraRef = useRef(null);
  const mountTimeRef = useRef(Date.now());
  const hasAttemptedRetry = useRef(false);

  const isFocused = useIsFocused();
  const [appState, setAppState] = useState(AppState.currentState);

  // Handle app state changes
  useEffect(() => {
    const subscription = AppState.addEventListener("change", (nextAppState) => {
      setAppState(nextAppState);
    });
    return () => subscription.remove();
  }, []);

  // Camera should be active when focused, app is active, and no preview
  const isActive = isFocused && appState === "active" && !previewImage;

  // Timeout to detect if camera doesn't initialize (process death scenario)
  useEffect(() => {
    if (!device) {
      const timeout = setTimeout(() => {
        if (!device && !hasAttemptedRetry.current) {
          hasAttemptedRetry.current = true;
          Alert.alert(
            "Camera Error",
            "Camera could not initialize. Please try again.",
            [
              {
                text: "Retry",
                onPress: () => {
                  navigation.goBack();
                  setTimeout(() => {
                    navigation.navigate("Camera", route.params);
                  }, 100);
                },
              },
              {
                text: "Cancel",
                onPress: () => navigation.goBack(),
                style: "cancel",
              },
            ]
          );
        }
      }, 5000);
      return () => clearTimeout(timeout);
    } else {
      hasAttemptedRetry.current = false;
    }
  }, [device, navigation, route.params]);

  if (device == null) {
    return (
      <View style={styles.centerContainer}>
        <ActivityIndicator size="large" color="#003366" />
        <Text>Loading camera...</Text>
      </View>
    );
  }

  return (
    <View style={StyleSheet.absoluteFill}>
      <Camera
        ref={cameraRef}
        style={StyleSheet.absoluteFill}
        device={device}
        isActive={isActive}
        photo={true}
        onError={(error) => console.error("Camera error:", error)}
        onInitialized={() => setCameraReady(true)}
        onStarted={() => console.log("Camera started streaming")}
        onStopped={() => console.log("Camera stopped streaming")}
      />
    </View>
  );
};

Relevant log output

// Timeout triggers after 5 seconds
09:17:59.649  ⚠️ Camera not available after 5019ms - possible process death

// After pressing "Retry" - component remounts but device is STILL null
09:18:03.433  '🔄 CameraScreen mounted - Timestamp:', '2026-01-19T12:18:03.433Z'
09:18:03.433  '📊 Initial state:', { hasPermission: true,
                                      device: 'null',
                                      isFocused: true,
                                      appState: 'active' }

// Timeout triggers again - stuck in infinite loop
09:18:08.450  ⚠️ Camera not available after 5022ms - possible process death

I don't see any VisionCamera logs when this error occurs. Only the console logs of my code.

Camera Device

When I play the problem, device comes out as null

Device

Samsung Galaxy S25+

VisionCamera Version

4.7.3

Can you reproduce this issue in the VisionCamera Example app?

No, I cannot reproduce the issue in the Example app

Additional information

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐛 bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions