Backgrounding an app on Screen 2 and resuming it sends me to Screen 1

Please provide the following:

  1. SDK Version: 49
  2. Platforms(Android/iOS/web/all): Android

TL:DR;
Flashing while using router.push() after launchImageLibraryAsync/launchCameraAsync finishes;
Added LoadingSpinner on Screen 1 to combat the flashing;
Backgrounding an app on Screen 2 and resuming it sends me to Screen 1’s LoadingSpinner which goes on forever;

I have a Home Screen with two buttons that open the gallery or the camera.
Once an image has been selected I use router.push() to send information about the image and navigate to the PreviewScreen.
The PreviewScreen receives the image and offers the user the possibility to send the image to an API or change the image.
For whatever reason, when finishing selecting the image, so when ImagePicker.launchCameraAsync finishes, I get sent back to the HomeScreen before going immediately to the PreviewScreen, causing a flashing.
In trying to fix this flashing I’ve added a state in the HomeScreen to check if I have selected an image.
const [imagePicked, setImagePicked] = useState(false);
If I have a selected image then show the spinner and instead of the HomeScreen flashing I have a nice loading spinner that acts as a transition between HomeScreen and PreviewScreen.

If I am on the PreviewScreen and I press on ChangeImage I get sent properly to the HomeScreen where setImagePicked((prevState) => false); works and sets imagePicked to false, making the HomeScreen work as intended.

The issue is that if I background the application while being on the PreviewScreen (exiting the app, without closing it) and then I go back to the app I get the HomeScreen’s Loading Spinner.

When I resume the app why don’t I get the PreviewScreen, since that is where I left the app at ?

If I comment the LoadingSpinner code from the HomeScreen and then I background the app while on the PreviewScreen, when I go back to the app I am still on the PreviewScreen.

Why isn’t resuming the app considered a focused event ?

console.log("HomeScreen:", imagePicked); logs true.

const HomeScreen = () => {
  const logo = require("assets/img/logo.png");

  const [imagePicked, setImagePicked] = useState(false);
  const navigation = useNavigation();

  console.log("HomeScreen:", imagePicked);

  useEffect(() => {
    console.log("HomeScreen mounted");
    const unsubscribe = navigation.addListener("focus", () => {
      console.log("HomeScreen focused");
      if (imagePicked) {
        setImagePicked((prevState) => false);
      }
    });

    return () => unsubscribe();
  }, [imagePicked, navigation]);

  const [cameraPermission, requestCameraPermission] =
    ImagePicker.useCameraPermissions();
  const [galleryPermission, requestGalleryPermission] =
    ImagePicker.useMediaLibraryPermissions();

  const requestAllPermissions = async () => {
    // First request camera permission
    await requestCameraPermission();
    // Then request gallery permission
    await requestGalleryPermission();
  };

  if (!galleryPermission || !cameraPermission) {
    // Camera permissions are still loading
    return <View />;
  }

  if (!galleryPermission.granted || !cameraPermission.granted) {
    // Camera and Image Gallery permissions are not granted yet
    return (
      <View style={styles.permissionContainer}>
        <Image source={logo} style={styles.img} />
        <Text style={styles.permissionText}>{GRANT_PERMISSION_TEXT}</Text>
        <Button
          onPress={requestAllPermissions}
          title="Grant Permissions"
          style={styles.permissionButton}
        />
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Image source={logo} style={styles.img} />
      {/*Open the image gallery*/}
      <OpenGallery setImagePicked={setImagePicked} />
      {/*Open the camera */}
      <OpenCamera setImagePicked={setImagePicked} />
      {imagePicked && (
        <LoadingSpinner
          visible={imagePicked}
          overlayColor={"rgba(34, 34, 34,  1)"}
        />
      )}
    </View>
  );
};

export default HomeScreen;
const OpenCamera = ({ setImagePicked }) => {
  const pickCamera = async () => {
    let result = await ImagePicker.launchCameraAsync({
      allowsEditing: true,
      quality: 1,
      mediaTypes: ImagePicker.MediaTypeOptions.Images,
      aspect: [1, 1],
    });

    if (!result.canceled) {
      const image = result.assets[0];
      setImagePicked(true);

      router.push({
        pathname: "/preview",
        params: {
          imageUri: image.uri,
          imageHeight: image.height,
          imageWidth: image.width,
        },
      });
    } else {
      // alert("You did not select any image.");
      setImagePicked(false);
    }
  };

  return <BTN label="Take a picture" icon={"camera"} onPress={pickCamera} />;
};

export default OpenCamera;
const PreviewScreen = () => {
  const params = useLocalSearchParams();
  const [compressedImage, setCompressedImage] = useState(null);
  const [error, setError] = useState(null);
  const selectedImage = {
    uri: params.imageUri,
    width: params.imageWidth,
    height: params.imageHeight,
  };

  const onCompressImage = async () => {
    setCompressedImage(await compressImage(selectedImage));
  };
  const onChangeImage = () =>
    router.canGoBack() ? router.back() : router.replace("/");

  if (!selectedImage.uri)
    return (
      <View style={styles.imageContainer}>
        <Text style={styles.text}>No image to preview</Text>
        <BTN label={"Go back"} onPress={() => router.replace("/")} />
      </View>
    );

  const reset = () => {
    setCompressedImage(null);
    setError(null);
  };

  return (
    <View style={styles.imageContainer}>
      <Image source={{ uri: selectedImage.uri }} style={styles.selectedImage} />
      {compressedImage && !error ? (
        <ResultBox image={compressedImage} error={error} setError={setError} />
      ) : (
        <>
          <ErrorModal visible={error} reset={reset} />
          <BTN label={"Send Image"} onPress={onCompressImage} icon={"send"} />
          <BTN label={"Change Image"} onPress={onChangeImage} />
        </>
      )}
    </View>
  );
};

export default PreviewScreen;
export default function Layout() {
  return (
    <Stack
      screenOptions={{
        headerTitleAlign: "center",
        headerStyle: {
          backgroundColor: "#f4511e",
        },
        headerTintColor: "#fff",
        headerTitleStyle: {
          fontWeight: "bold",
        },
      }}
    >
      <Stack.Screen name="index" options={{ headerTitle: "Home" }} />
      <Stack.Screen name="preview" options={{ headerTitle: "Preview" }} />
      <Stack.Screen name="result" options={{ headerTitle: "Result" }} />
    </Stack>
  );
}

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.