Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useFrameprocessor still executed when screen is inactive 🐛 #1161

Closed
3 of 4 tasks
baylesa-dev opened this issue Jul 25, 2022 · 6 comments
Closed
3 of 4 tasks

useFrameprocessor still executed when screen is inactive 🐛 #1161

baylesa-dev opened this issue Jul 25, 2022 · 6 comments
Labels
🐛 bug Something isn't working

Comments

@baylesa-dev
Copy link

baylesa-dev commented Jul 25, 2022

What were you trying to do?

Hi there! First, thank you for the great job, this lib is very nice !

I'm implementing an OCR feature in my app. I'm using useFrameProcessor with aarongrider/vision-camera-ocr plugin.

Reproduceable Code

export default function Scan() {
    const devices = useCameraDevices()
    const isFocused = useIsFocused()

    const frameProcessor = useFrameProcessor(frame => {
        'worklet'

        const scannedOcr = scanOCR(frame)

        console.log(scannedOcr.result)
    }, [])

    if (!devices.back) {
        return (
            <DefaultContainer withBackButton headerTitle="Scan">
                <ExpandedWrapper>
                    <ActivityIndicator size="large" color={colors.primary} />
                </ExpandedWrapper>
            </DefaultContainer>
        )
    }

    return (
        <Camera
            preset="high"
            isActive={isFocused}
            device={devices.back}
            videoStabilizationMode="auto"
            frameProcessorFps={5}
            frameProcessor={frameProcessor}
            style={StyleSheet.absoluteFill}
        />
    )
}

What happened instead?

To debug my code, I log the result of the plugin. When I move out of the screen (with React Navigation, goBack, navigate, replace, ...), the callback function is still executed.
The plugin is still able to parse what my camera sees.

package.json:

{
  "dependencies": {
    "@react-navigation/native": "^6.0.10",
    "@react-navigation/native-stack": "^6.6.2",
    "react-native": "0.69.0",
    "react-native-reanimated": "2.9.1",
  }
}

Relevant log output

LOG  Unmount
 LOG  {"blocks": [], "text": ""}
 LOG  {"blocks": [], "text": ""}

Device

iPhone SE 2020 - 15.5

VisionCamera Version

2.14.0

Additional information

@baylesa-dev baylesa-dev added the 🐛 bug Something isn't working label Jul 25, 2022
@baylesa-dev
Copy link
Author

Related to #905 and software-mansion/react-native-reanimated#3124

@baylesa-dev
Copy link
Author

Applying this patch seems enough for now:

react-native-reanimated+2.9.1.patch

diff --git a/node_modules/react-native-reanimated/ios/LayoutReanimation/REAAnimationsManager.m b/node_modules/react-native-reanimated/ios/LayoutReanimation/REAAnimationsManager.m
index 9f6cbf9..c8a8b64 100644
--- a/node_modules/react-native-reanimated/ios/LayoutReanimation/REAAnimationsManager.m
+++ b/node_modules/react-native-reanimated/ios/LayoutReanimation/REAAnimationsManager.m
@@ -22,8 +22,8 @@ @implementation REAAnimationsManager {
   RCTUIManager *_uiManager;
   REAUIManager *_reaUiManager;
   NSMutableDictionary<NSNumber *, NSNumber *> *_states;
-  NSMutableDictionary<NSNumber *, UIView *> *_viewForTag;
-  NSMutableSet<NSNumber *> *_toRemove;
+  NSMutableDictionary<NSNumber *, UIView *> *_viewsToRemove;
+  NSMutableDictionary<NSNumber *, UIView *> *_viewsWithExitingAnimation;
   NSMutableArray<NSString *> *_targetKeys;
   NSMutableArray<NSString *> *_currentKeys;
   BOOL _cleaningScheduled;
@@ -45,8 +45,8 @@ - (instancetype)initWithUIManager:(RCTUIManager *)uiManager
     _uiManager = uiManager;
     _reaUiManager = (REAUIManager *)uiManager;
     _states = [NSMutableDictionary new];
-    _viewForTag = [NSMutableDictionary new];
-    _toRemove = [NSMutableSet new];
+    _viewsToRemove = [NSMutableDictionary new];
+    _viewsWithExitingAnimation = [NSMutableDictionary new];
     _cleaningScheduled = false;
 
     _targetKeys = [NSMutableArray new];
@@ -65,8 +65,8 @@ - (void)invalidate
   _removeConfigForTag = nil;
   _uiManager = nil;
   _states = nil;
-  _viewForTag = nil;
-  _toRemove = nil;
+  _viewsToRemove = nil;
+  _viewsWithExitingAnimation = nil;
   _cleaningScheduled = false;
   _targetKeys = nil;
   _currentKeys = nil;
@@ -119,20 +119,20 @@ - (void)findRoot:(UIView *)view roots:(NSMutableSet<NSNumber *> *)roots
   }
 }
 
-- (BOOL)dfs:(UIView *)root view:(UIView *)view cands:(NSMutableSet<NSNumber *> *)cands
+- (BOOL)dfs:(UIView *)root view:(UIView *)view
 {
   NSNumber *tag = view.reactTag;
   if (tag == nil) {
     return true;
   }
-  if (![cands containsObject:tag] && _states[tag] != nil) {
+  if (_viewsToRemove[tag] == nil && _states[tag] != nil) {
     return true;
   }
   BOOL cannotStripe = false;
   NSArray<UIView *> *toRemoveCopy = [view.reactSubviews copy];
   for (UIView *child in toRemoveCopy) {
     if (![view isKindOfClass:[RCTTextView class]]) {
-      cannotStripe |= [self dfs:root view:child cands:cands];
+      cannotStripe |= [self dfs:root view:child];
     }
   }
   if (!cannotStripe) {
@@ -140,26 +140,35 @@ - (BOOL)dfs:(UIView *)root view:(UIView *)view cands:(NSMutableSet<NSNumber *> *
       [_reaUiManager unregisterView:view];
     }
     [_states removeObjectForKey:tag];
-    [_viewForTag removeObjectForKey:tag];
-    [_toRemove removeObject:tag];
+    [_viewsToRemove removeObjectForKey:tag];
+    [_viewsWithExitingAnimation removeObjectForKey:tag];
   }
   return cannotStripe;
 }
 
+- (UIView *)findView:(NSNumber *)tag
+{
+  UIView *view = _viewsToRemove[tag];
+  if (view != nil) {
+    return view;
+  }
+  view = [_reaUiManager viewForReactTag:tag];
+  if (view != nil) {
+    return view;
+  }
+  return _viewsWithExitingAnimation[tag];
+}
+
 - (void)removeLeftovers
 {
   NSMutableSet<NSNumber *> *roots = [NSMutableSet new];
-  for (NSNumber *viewTag in _toRemove) {
-    UIView *view = _viewForTag[viewTag];
-    if (view == nil) {
-      view = [_reaUiManager viewForReactTag:viewTag];
-      _viewForTag[viewTag] = view;
-    }
+  for (NSNumber *key in _viewsToRemove) {
+    UIView *view = _viewsToRemove[key];
     [self findRoot:view roots:roots];
   }
   for (NSNumber *viewTag in roots) {
-    UIView *view = _viewForTag[viewTag];
-    [self dfs:view view:view cands:_toRemove];
+    UIView *view = [self findView:viewTag];
+    [self dfs:view view:view];
   }
 }
 
@@ -171,9 +180,9 @@ - (void)notifyAboutEnd:(NSNumber *)tag cancelled:(BOOL)cancelled
       _states[tag] = [NSNumber numberWithInt:Layout];
     }
     if (state == Disappearing) {
-      _states[tag] = [NSNumber numberWithInt:ToRemove];
-      if (tag != nil) {
-        [_toRemove addObject:tag];
+      UIView *view = [self findView:tag];
+      if (view != nil) {
+        [_viewsToRemove setObject:view forKey:tag];
       }
       [self scheduleCleaning];
     }
@@ -192,7 +201,8 @@ - (void)notifyAboutProgress:(NSDictionary *)newStyle tag:(NSNumber *)tag
 
   NSMutableDictionary *dataComponenetsByName = [_uiManager valueForKey:@"_componentDataByName"];
   RCTComponentData *componentData = dataComponenetsByName[@"RCTView"];
-  [self setNewProps:[newStyle mutableCopy] forView:_viewForTag[tag] withComponentData:componentData];
+  UIView *view = [self findView:tag];
+  [self setNewProps:[newStyle mutableCopy] forView:view withComponentData:componentData];
 }
 
 - (double)getDoubleOrZero:(NSNumber *)number
@@ -299,12 +309,13 @@ - (void)onViewRemoval:(UIView *)view before:(REASnapshot *)before
   if (state == Inactive) {
     if (startValues != nil) {
       _states[tag] = [NSNumber numberWithInt:ToRemove];
-      [_toRemove addObject:tag];
+      [_viewsToRemove setObject:view forKey:tag];
       [self scheduleCleaning];
     }
     return;
   }
   _states[tag] = [NSNumber numberWithInt:Disappearing];
+  [_viewsWithExitingAnimation setObject:view forKey:tag];
   NSDictionary *preparedValues = [self prepareDataForAnimatingWorklet:startValues frameConfig:ExitingFrame];
   _startAnimationForTag(tag, @"exiting", preparedValues, @(0));
 }
@@ -315,7 +326,6 @@ - (void)onViewCreate:(UIView *)view after:(REASnapshot *)after
   NSNumber *tag = view.reactTag;
   if (_states[tag] == nil) {
     _states[tag] = [NSNumber numberWithInt:Inactive];
-    _viewForTag[tag] = view;
   }
   NSMutableDictionary *targetValues = after.values;
   ViewState state = [_states[tag] intValue];

@mrousavy
Copy link
Owner

Oh so it's a REA bug - can you report it there?

@wilav-dev
Copy link

Same issue

@jackstudd
Copy link

@baylesa-dev This patch works but since it's considered dangerous in https://github.com/software-mansion/react-native-reanimated/pull/3157/files and wasn't merged I just temporarily removed all LayoutAnimations (didn't have a ton of them)

@aditya-984
Copy link

##905 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants