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

Android crash: This dynamic value has been recycled #806

Closed
janicduplessis opened this issue Oct 10, 2018 · 56 comments
Closed

Android crash: This dynamic value has been recycled #806

janicduplessis opened this issue Oct 10, 2018 · 56 comments

Comments

@janicduplessis
Copy link
Contributor

janicduplessis commented Oct 10, 2018

I'm seeing this crash log on Android in production since updating to ^7.0.0. I'm not sure how to reproduce locally but it comes a svg component that is animated using native animated. However I can't reproduce the crash reliably so there must be some kind of race condition, it happens rather rarely, ~20 instances in the past week for a few thousand users.

I noticed the implementation uses shadow nodes to save the svg data but if I understand correctly it could just be normal uithread view manager props. Shadow nodes run on a different thread so it might be what causes this race condition.

Here's the full stacktrace if that can be useful, the interesting part is the inner exception.

JSApplicationIllegalArgumentException
Error while updating property 'stroke' of a view managed by: RNSVGRect
com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter in updateViewProp at line 95
com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter in setProperty at line 132
com.facebook.react.uimanager.ViewManagerPropertyUpdater in updateProps at line 51
com.facebook.react.uimanager.ViewManager in updateProperties at line 34
com.facebook.react.uimanager.NativeViewHierarchyManager in createView at line 269
com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation in execute at line 200
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in dispatchPendingNonBatchedOperations at line 1105
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in doFrameGuarded at line 1076
com.facebook.react.uimanager.GuardedFrameCallback in doFrame at line 29
com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher in doFrame at line 134
com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1 in doFrame at line 105
android.view.Choreographer$CallbackRecord in run at line 869
android.view.Choreographer in doCallbacks at line 683
android.view.Choreographer in doFrame at line 616
android.view.Choreographer$FrameDisplayEventReceiver in run at line 857
android.os.Handler in handleCallback at line 751
android.os.Handler in dispatchMessage at line 95
android.os.Looper in loop at line 154
android.app.ActivityThread in main at line 6154
java.lang.reflect.Method in invoke
com.android.internal.os.ZygoteInit$MethodAndArgsCaller in run at line 867
com.android.internal.os.ZygoteInit in main at line 757
InvocationTargetException
java.lang.reflect.Method in invoke
com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter in updateViewProp at line 83
com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter in setProperty at line 132
com.facebook.react.uimanager.ViewManagerPropertyUpdater in updateProps at line 51
com.facebook.react.uimanager.ViewManager in updateProperties at line 34
com.facebook.react.uimanager.NativeViewHierarchyManager in createView at line 269
com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation in execute at line 200
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in dispatchPendingNonBatchedOperations at line 1105
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in doFrameGuarded at line 1076
com.facebook.react.uimanager.GuardedFrameCallback in doFrame at line 29
com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher in doFrame at line 134
com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1 in doFrame at line 105
android.view.Choreographer$CallbackRecord in run at line 869
android.view.Choreographer in doCallbacks at line 683
android.view.Choreographer in doFrame at line 616
android.view.Choreographer$FrameDisplayEventReceiver in run at line 857
android.os.Handler in handleCallback at line 751
android.os.Handler in dispatchMessage at line 95
android.os.Looper in loop at line 154
android.app.ActivityThread in main at line 6154
java.lang.reflect.Method in invoke
com.android.internal.os.ZygoteInit$MethodAndArgsCaller in run at line 867
com.android.internal.os.ZygoteInit in main at line 757
IllegalStateException
This dynamic value has been recycled
com.facebook.react.bridge.DynamicFromMap in asString at line 78
com.horcrux.svg.RenderableShadowNode in setStroke at line 139
com.horcrux.svg.RenderableViewManager in setStroke at line 723
java.lang.reflect.Method in invoke
com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter in updateViewProp at line 83
com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter in setProperty at line 132
com.facebook.react.uimanager.ViewManagerPropertyUpdater in updateProps at line 51
com.facebook.react.uimanager.ViewManager in updateProperties at line 34
com.facebook.react.uimanager.NativeViewHierarchyManager in createView at line 269
com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation in execute at line 200
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in dispatchPendingNonBatchedOperations at line 1105
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in doFrameGuarded at line 1076
com.facebook.react.uimanager.GuardedFrameCallback in doFrame at line 29
com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher in doFrame at line 134
com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1 in doFrame at line 105
android.view.Choreographer$CallbackRecord in run at line 869
android.view.Choreographer in doCallbacks at line 683
android.view.Choreographer in doFrame at line 616
android.view.Choreographer$FrameDisplayEventReceiver in run at line 857
android.os.Handler in handleCallback at line 751
android.os.Handler in dispatchMessage at line 95
android.os.Looper in loop at line 154
android.app.ActivityThread in main at line 6154
java.lang.reflect.Method in invoke
com.android.internal.os.ZygoteInit$MethodAndArgsCaller in run at line 867
com.android.internal.os.ZygoteInit in main at line 757
@Almouro
Copy link

Almouro commented Oct 10, 2018

Hi @janicduplessis, I'm also seeing a fair amount of crash reports with a similar error since updating to 7.0.2.
Which react-native-svg version are you using?

@msand
Copy link
Collaborator

msand commented Oct 10, 2018

I wonder if it could be related to this: c39b326
Because this probably changed on what thread the rendering is done.

But, it seems more like the ViewManagerPropertyUpdater uses an incorrect FallbackShadowNodeSetter to set the fill property, somehow it seems to confuse the fill property with a MutableYogaValue and calls LayoutShadowNode.setPositionValues on it, which leads to this line: https://github.com/facebook/react-native/blob/0.57-stable/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java#L65

It seems to be missing a check for the number type before calling dynamic.asDouble()

     else if (dynamic.getType() == ReadableType.Number) {
       unit = YogaUnit.POINT;
       value = PixelUtil.toPixelFromDIP(dynamic.asDouble());
     }

I wonder why it doesn't use the setter from the view manager:
https://github.com/react-native-community/react-native-svg/blob/v7.0.3/android/src/main/java/com/horcrux/svg/RenderableViewManager.java#L707

and the shadow node:
https://github.com/react-native-community/react-native-svg/blob/v7.0.3/android/src/main/java/com/horcrux/svg/RenderableShadowNode.java#L80

Tricky to analyse without a reproduction.

@msand
Copy link
Collaborator

msand commented Oct 10, 2018

Currently, the Views on Android are only used to get access to the shadow nodes for native animation: https://github.com/react-native-community/react-native-svg/blob/master/android/src/main/java/com/horcrux/svg/RenderableView.java#L8
Essentially all the data and logic is in the shadow nodes for now. Only the svg root has a View which gets attached to the render tree, and it only renders lazily (by calling into the shadow node) and caches the bitmap until the next invalidation. I suspect this might cause some race conditions, if the shadow nodes / trees are modified, while the svg root is rendering the bitmap.

@janicduplessis
Copy link
Contributor Author

Actually I think there might be 2 separate issues. I linked the wrong stacktrace in the initial issue. Here’s the one that seems to be related to the race condition I was talking about.

JSApplicationIllegalArgumentException
Error while updating property 'stroke' of a view managed by: RNSVGRect
com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter in updateViewProp at line 95
com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter in setProperty at line 132
com.facebook.react.uimanager.ViewManagerPropertyUpdater in updateProps at line 51
com.facebook.react.uimanager.ViewManager in updateProperties at line 34
com.facebook.react.uimanager.NativeViewHierarchyManager in createView at line 269
com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation in execute at line 200
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in dispatchPendingNonBatchedOperations at line 1105
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in doFrameGuarded at line 1076
com.facebook.react.uimanager.GuardedFrameCallback in doFrame at line 29
com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher in doFrame at line 134
com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1 in doFrame at line 105
android.view.Choreographer$CallbackRecord in run at line 869
android.view.Choreographer in doCallbacks at line 683
android.view.Choreographer in doFrame at line 616
android.view.Choreographer$FrameDisplayEventReceiver in run at line 857
android.os.Handler in handleCallback at line 751
android.os.Handler in dispatchMessage at line 95
android.os.Looper in loop at line 154
android.app.ActivityThread in main at line 6154
java.lang.reflect.Method in invoke
com.android.internal.os.ZygoteInit$MethodAndArgsCaller in run at line 867
com.android.internal.os.ZygoteInit in main at line 757
InvocationTargetException
java.lang.reflect.Method in invoke
com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter in updateViewProp at line 83
com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter in setProperty at line 132
com.facebook.react.uimanager.ViewManagerPropertyUpdater in updateProps at line 51
com.facebook.react.uimanager.ViewManager in updateProperties at line 34
com.facebook.react.uimanager.NativeViewHierarchyManager in createView at line 269
com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation in execute at line 200
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in dispatchPendingNonBatchedOperations at line 1105
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in doFrameGuarded at line 1076
com.facebook.react.uimanager.GuardedFrameCallback in doFrame at line 29
com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher in doFrame at line 134
com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1 in doFrame at line 105
android.view.Choreographer$CallbackRecord in run at line 869
android.view.Choreographer in doCallbacks at line 683
android.view.Choreographer in doFrame at line 616
android.view.Choreographer$FrameDisplayEventReceiver in run at line 857
android.os.Handler in handleCallback at line 751
android.os.Handler in dispatchMessage at line 95
android.os.Looper in loop at line 154
android.app.ActivityThread in main at line 6154
java.lang.reflect.Method in invoke
com.android.internal.os.ZygoteInit$MethodAndArgsCaller in run at line 867
com.android.internal.os.ZygoteInit in main at line 757
IllegalStateException
This dynamic value has been recycled
com.facebook.react.bridge.DynamicFromMap in asString at line 78
com.horcrux.svg.RenderableShadowNode in setStroke at line 139
com.horcrux.svg.RenderableViewManager in setStroke at line 723
java.lang.reflect.Method in invoke
com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter in updateViewProp at line 83
com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter in setProperty at line 132
com.facebook.react.uimanager.ViewManagerPropertyUpdater in updateProps at line 51
com.facebook.react.uimanager.ViewManager in updateProperties at line 34
com.facebook.react.uimanager.NativeViewHierarchyManager in createView at line 269
com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation in execute at line 200
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in dispatchPendingNonBatchedOperations at line 1105
com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback in doFrameGuarded at line 1076
com.facebook.react.uimanager.GuardedFrameCallback in doFrame at line 29
com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher in doFrame at line 134
com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1 in doFrame at line 105
android.view.Choreographer$CallbackRecord in run at line 869
android.view.Choreographer in doCallbacks at line 683
android.view.Choreographer in doFrame at line 616
android.view.Choreographer$FrameDisplayEventReceiver in run at line 857
android.os.Handler in handleCallback at line 751
android.os.Handler in dispatchMessage at line 95
android.os.Looper in loop at line 154
android.app.ActivityThread in main at line 6154
java.lang.reflect.Method in invoke
com.android.internal.os.ZygoteInit$MethodAndArgsCaller in run at line 867
com.android.internal.os.ZygoteInit in main at line 757

@janicduplessis
Copy link
Contributor Author

@Almouro 7.0.3

@msand
Copy link
Collaborator

msand commented Oct 10, 2018

Thanks for this, could you try with the latest commit from the master branch?

@msand
Copy link
Collaborator

msand commented Oct 10, 2018

Could you post the code or a small reproduction that can produce it? I'm not sure how the dynamic value could be recycled, perhaps it isn't even a string? At least react-native-svg doesn't make any recycle calls on any dynamic values.

@janicduplessis
Copy link
Contributor Author

Here's the code for the component https://gist.github.com/janicduplessis/87a859eda656806bd2dea0db0a8940f1

I'm planning a new release in the next few days, I will update to master.

@janicduplessis
Copy link
Contributor Author

Actually I think the first crash is related to changes I made locally to try to fix the 2nd stack trace I linked. I'll update the issue to only include the This dynamic value has been recycled crash. Sorry about that.

@janicduplessis janicduplessis changed the title Android crash: Value for fill cannot be cast from ReadableNativeArray to Double Android crash: This dynamic value has been recycled Oct 10, 2018
@msand
Copy link
Collaborator

msand commented Oct 10, 2018

I've been testing this code for some time now and haven't been able to observe any exceptions. Not sure how to trigger it:

// @flow

import * as React from "react";
import { Button, StyleSheet, View, Animated } from "react-native";
import Svg, { Line, Circle } from "react-native-svg";

const AnimatedLine = Animated.createAnimatedComponent(Line);
const AnimatedCircle = Animated.createAnimatedComponent(Circle);

type Props = {
  style?: any,
  backgroundIsTurquoise?: boolean,
};
type State = {
  anim: Animated.Value,
};

class Loading extends React.Component<Props, State> {
  state = {
    anim: new Animated.Value(0),
    hide: false,
  };

  componentDidMount() {
    Animated.loop(
      Animated.timing(this.state.anim, {
        duration: 2000,
        toValue: 1,
        isInteraction: false,
        useNativeDriver: true,
      }),
    ).start();
  }

  render() {
    const opacity = this.state.anim.interpolate({
      inputRange: [0, 0.93, 1],
      outputRange: [1, 1, 0],
    });
    const yellowBarOffset = this.state.anim.interpolate({
      inputRange: [0, 0.2, 1],
      outputRange: [22, 0, 0],
    });
    const greenBarOffset = this.state.anim.interpolate({
      inputRange: [0, 0.19, 0.4, 1],
      outputRange: [30.01, 30.01, 0, 0],
    });
    const pinkBarOffset = this.state.anim.interpolate({
      inputRange: [0, 0.4, 0.78, 1],
      outputRange: [107, 107, 50, 50],
    });

    const secondLineColor = this.props.backgroundIsTurquoise
      ? "white"
      : "turquoise";
    const { hide } = this.state;

    return (
      <View>
        <Button
          title="Toggle"
          onPress={() => this.setState(({ hide }) => ({ hide: !hide }))}
        />
        <Animated.View style={[{ opacity }, this.props.style]}>
          {hide ? null : (
            <Svg width={70} height={70}>
              <AnimatedLine
                stroke={secondLineColor}
                strokeWidth="8"
                strokeLinecap="round"
                strokeDasharray={[30]}
                strokeDashoffset={greenBarOffset}
                x1="48"
                y1="15"
                x2="29"
                y2="34.2"
              />
              <AnimatedCircle
                fill="transparent"
                stroke="pink"
                strokeWidth="8"
                strokeLinecap="round"
                strokeDasharray={[107]}
                strokeDashoffset={pinkBarOffset}
                rotation="-127"
                origin="36, 44"
                cx="36"
                cy="44"
                r="12"
              />
              <AnimatedLine
                stroke="yellow"
                strokeWidth="8.5"
                strokeLinecap="round"
                strokeDasharray={[22]}
                strokeDashoffset={yellowBarOffset}
                x1="26"
                y1="14.5"
                x2="48"
                y2="14.5"
              />
            </Svg>
          )}
        </Animated.View>
      </View>
    );
  }
}

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Loading />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: "column",
    backgroundColor: "beige",
  },
});

@janicduplessis
Copy link
Contributor Author

@msand Thanks for trying it out, I can't reproduce the issue neither on my end and it seems to happen very rarely. Hopefully we can figure something out from the stacktrace or other people hit this crash too.

@Almouro
Copy link

Almouro commented Oct 12, 2018

Hi guys,

Yesterday got ~1k crashes quite similar for about ~20k users on the app yesterday.

Crashes we are getting are usually:

  • This dynamic value has been recycled
  • java.lang.ClassCastException: com.facebook.react.bridge.ReadableNativeArray cannot be cast to java.lang.Double at com.facebook.react.bridge.ReadableNativeMap.getDouble(ReadableNativeMap.java:147)
  • and java.lang.ArrayIndexOutOfBoundsException: length=10; index=-1 at android.support.v4.util.Pools$SimplePool.release(Pools.java:116) at com.facebook.react.bridge.DynamicFromMap.recycle(DynamicFromMap.java:40)

These are new bugs in our last release that included an upgrade (among other things of course) of react-native-svg from 6.5.1 to 7.3.0.

All of those bugs seem to touch the SimplePoll recycling and upon investigation I found this PR facebook/react-native#17842 which makes the SimplePool in DynamicFromMap thread safe.

Investigating with Android Studio debugger by setting breakpoints in DynamicFromMap.create in here, I found that this method was called by 2 threads:

  • mqt_native_modules for basic RN components
  • main only for react-native-svg

I also saw that react-native-svg is using Dynamic since version 7 of the lib (3879c90)

So it seems like the issue could be:

  • react-native-svg started using Dynamic
  • but SimplePool in DynamicFromMap is not thread safe
  • and react-native-svg uses a different thread than default RN one

I can try downgrading react-native-svg or applying the PR above and build the app with the forked React Native version to validate that.

What do you guys think? Where is react-native-svg using a different thread?

@msand
Copy link
Collaborator

msand commented Oct 12, 2018

I guess it's related to the native animation driver when it's setting the animated properties, I think it runs on the main ui thread. It's quite likely that the PR would fix it, would be great if you can test it :+1

@Almouro
Copy link

Almouro commented Oct 12, 2018

@msand 3879c90 is rolling out for 10% of our users now.
I'll let you know how it goes :)

@Almouro
Copy link

Almouro commented Oct 13, 2018

@msand I confirm that this issue has disappeared 🎉 for those 10% including the PR on React Native (facebook/react-native#17842)
I'll push this PR on React Native side, but might I ask: why is it that other components being animated with the native driver don't trigger this exception while react-native-svg components do?

Our biggest crash on that newest release is now:

Caused by: java.lang.NullPointerException: 
  at com.horcrux.svg.RenderableViewManager$6.setR (RenderableViewManager.java:237)

I can open a new issue for it, I don't think it's related

@msand
Copy link
Collaborator

msand commented Oct 13, 2018

@Almouro Great! Thanks for the info.
I guess the other components don't use dynamic as the type of any parameters which are animated. I haven't been able to observe the error myself, so haven't been able to dig deeper.
I think the other error is probably something else, opening a new issue is probably appropriate yes.

@msand
Copy link
Collaborator

msand commented Oct 13, 2018

@janicduplessis Could you champion getting that PR merged for 0.58? or 0.57.4?

@msand
Copy link
Collaborator

msand commented Oct 13, 2018

@Almouro Can you try v7.1.0 I suspect 1e25870 to be the culprit.

@janicduplessis
Copy link
Contributor Author

@msand Sure, I was about to also ship the PR to test if it fixes the issue but it seems like it does :)

@janicduplessis
Copy link
Contributor Author

Native Animated does not work with layout props so its probably just those ones that use Dynamic.

@janicduplessis
Copy link
Contributor Author

@msand AFAIK Dynamic was implemented to support props with multiple possible types like for example style.width can be either a number or a string when using percent units. Other than that I don't think it should be used since like you said there is a small perf hit.

@msand
Copy link
Collaborator

msand commented Oct 14, 2018

@Almouro Can you try with the latest commit from the master branch? I've simplified the dynamic property setters in android and improved the null handling logic.

@msand
Copy link
Collaborator

msand commented Oct 14, 2018

There's a potentially significant optimisation opportunity in the property handling, for any props which currently take a string to allow for units. There's a redundant round-trip from a double to a string back to a double, when animating the properties (or whenever the given value is a double / Number). The common case is probably a unit-less number anyway, so it would make sense to optimise for that. To maintain spec-conformance, it would require adding an enum for the units, another field signifying the unit for each property, and, that the property setters would handle the case when the value is a string, such that it sets the unit correctly. And finally, the relativeOnWidth/Height/Other (css units to pixels resolvers) would need to accept a number and a enum unit instead of a string.

@msand
Copy link
Collaborator

msand commented Oct 14, 2018

Another optimisation opportunity would be to rename the fields such that the propertyNameToFieldName could be removed.

@msand
Copy link
Collaborator

msand commented Oct 14, 2018

Also, as @janicduplessis wrote. The shadow nodes could be removed, by creating separate View classes and moving the logic from the shadow nodes there instead. Because the SvgViewManager returns true for needsCustomLayoutForChildren anyway, and we're already creating a View for each element (to allow for animation). So it should actually conserve memory, and possibly improve performance as well. Or are there any benefits to having the shadow nodes I'm unaware of? As we're not using yoga for layout (except for the root svg element position and dimension) they should just be redundant, right?

@msand
Copy link
Collaborator

msand commented Oct 14, 2018

At least currently, having the shadow nodes causes an extra de-referencing for each time a property is set using the ViewManagers, and we keep a

    private final SparseArray<T> mTagToShadowNode = new SparseArray<>();

to get a reference to it (costing memory and accounting on View creation/destruction), which wouldn't be needed if the logic was simply inside the Views instead.

@msand
Copy link
Collaborator

msand commented Oct 14, 2018

I now have a branch where I've moved the logic into the Views and almost completely removed the ShadowNodes. 0bdca66
It certainly seems to perform better.

@msand
Copy link
Collaborator

msand commented Oct 14, 2018

@msageryd Could you try your app with the latest commit from master and the one from the plain-views branch to see if there's any significant changes? https://github.com/react-native-community/react-native-svg/compare/plain-views

@Almouro
Copy link

Almouro commented Oct 15, 2018

@msand I opened a new issue for the new bug. I don't think it has to do with this issue anymore :)

@janicduplessis
Copy link
Contributor Author

@msand I think removing shadow nodes on Android makes sense, iOS already uses views only.

@msand
Copy link
Collaborator

msand commented Oct 15, 2018

The current latest commit in the plain-views branch seems to work in all tests I have quickly testable. Don't see any reasons not to cut another release at this point. Unless you know of any regressions?
Could perhaps still do the refactoring to optimise for doubles / unitless numbers, but I'm not sure when exactly I would have time to finish that.

@msand
Copy link
Collaborator

msand commented Oct 17, 2018

@janicduplessis Would it be possible to get that PR cherrypicked for v0.57.4? Seems it should probably be the recommended minimum for any version of react-native-svg using Dynamic. And the plain views branch should probably become the recommended v7 version, to eliminate the null exceptions.

@msand
Copy link
Collaborator

msand commented Oct 18, 2018

I've implemented the optimizations in the SVGLength branch now: https://github.com/react-native-community/react-native-svg/compare/SVGLength
Commit msg: Optimize setting properties and animation: Implement SVGLength

Removes redundant round-trip (double > string > double) when animating.
Optimizes for the case when dynamic arguments are numbers.
Improves memory consumption and cpu load.

@msand
Copy link
Collaborator

msand commented Oct 18, 2018

The css value resolvers could still be made to get the canvas width/height and font-size only when needed, instead of every time.

@msand
Copy link
Collaborator

msand commented Oct 18, 2018

Implemented fast path for css resolvers, android: 2a449c3 ios: 00f0b66

@msand
Copy link
Collaborator

msand commented Oct 18, 2018

I've fixed all known remaining regressions from the rewrite now: https://github.com/react-native-community/react-native-svg/compare/SVGLength
Now it should be more spec conformant, stable, faster, memory efficient and easier to read.

@janicduplessis
Copy link
Contributor Author

@msand I can post in the release repo to get it included in the next minor release if there is one.

Nice! Is that on npm? I'm planning a release of my app soon so I can test it.

@msand
Copy link
Collaborator

msand commented Oct 19, 2018

@janicduplessis Excellent! Now it is, v7.2.0 just published 🎉 https://www.npmjs.com/package/react-native-svg/v/7.2.0

@msageryd
Copy link

@msand Sorry for being late to the game. Every performance optimisation is great news to me. Unfortunately I ran into a wall here. I don't know where to start searching.

This is what I get when I mount the "drawing view" in my app using RNSVG 7.2
image

I have searched through my code in the hope to find any place where I have used strings instead of numbers. I only found one place, but changing this to numbers didn't fix the problem.

The reason I have one place where I'm using strings is that width and height of <Use> did not accept numbers previously. Should I use numbers in 7.2?

Here is my previous workaround in order to get Useto work:

      <Use
        href={this.getSymbolHref()}
        transform={transform}
        x={pos.x}
        y={pos.y}
        width={pos.symbolSize + ''}
        height={pos.symbolSize + ''}
      />

Do you have any clues of what to look for?

@msageryd
Copy link

I have dug into this. I managed to isolate the problem to a very simple line drawing.

This works:

return (
      <G>
        <Line x1={'10'} y1={'40'} x2={'40'} y2={'40'} stroke={'gray'} strokeWidth={8} />
      </G>
    );

This does not work:

return (
      <G>
        <Line x1={10} y1={40} x2={40} y2={40} stroke={'gray'} strokeWidth={8} />
      </G>
    );

The coordinates must be strings to work. The strokeWidth can be numerical, though.

I also got the below warning:
I have set pointerEvents to "none" on my Svg element. I don't set pointerEvents at G elements, though. This seems to be something RNSVG does internaly.

image

This is how the properties of my Svg element is set:

<Svg
  width={data.viewPortRect.width()}
  height={data.viewPortRect.height()}
  pointerEvents={'none'}
>

@msand
Copy link
Collaborator

msand commented Oct 19, 2018

@msageryd Hmm, both those examples (Lines) work fine for me in v7.2.0
I merged the PR from @janicduplessis to remove prop-types and released v8.0.0, so that warning won't be bothering you again ;)

@msand
Copy link
Collaborator

msand commented Oct 19, 2018

I've made the Svg element return a G element and set some of the styles and props from the root element on it, to allow inheritance of values without another significant refactor, should perhaps omit a bit more of the properties, but don't know of any actual issues that could result from it as of now. So, all Svg content currently have an implicit G element in the root.

@msand
Copy link
Collaborator

msand commented Oct 19, 2018

@msageryd Regarding numbers and strings, I recommend using numbers, but both should work, it's just that numbers are cheaper with regards to memory, cpu and energy. Much of the recent work has been to optimize for the case when the arguments are plain numbers rather than string encoded.

@msand
Copy link
Collaborator

msand commented Oct 19, 2018

@msageryd From the error message, it seems like these two lines would be missing from the code you've built: https://github.com/react-native-community/react-native-svg/blob/75204047c9424c591ed42d9763d6547709cf2b8b/ios/ViewManagers/RNSVGNodeManager.m#L176-L177
Can you try a clean rebuild with v8?
Otherwise, can you try adding those two lines somewhere together with these (e.g. before or after, but replace RNSVGNode with RNSVGUse) : https://github.com/react-native-community/react-native-svg/blob/75204047c9424c591ed42d9763d6547709cf2b8b/ios/ViewManagers/RNSVGUseManager.m#L21-L32

@msand
Copy link
Collaborator

msand commented Oct 19, 2018

@msageryd perhaps you were using the plain-views branch? I tested in the master branch (essentially the SVGLength branch + some minor fixes, which builds on the plain-views one).

@janicduplessis
Copy link
Contributor Author

Good news, the fix will make it in the next rn minor react-native-community/releases#48 (comment)

@janicduplessis
Copy link
Contributor Author

@msand I'm seeing a visual issue with the component I sent you earlier (https://gist.github.com/janicduplessis/87a859eda656806bd2dea0db0a8940f1) on iOS 8.0.0, haven't tested android yet.

@msand
Copy link
Collaborator

msand commented Oct 19, 2018

Thanks for reporting, will look at it later tonight once I get back to a computer

@janicduplessis
Copy link
Contributor Author

@msand Thanks!!

@msand
Copy link
Collaborator

msand commented Oct 19, 2018

@janicduplessis I think I've fixed the issue, really wouldn't expect this to be necessary changes to the code. But oh well, yet another day to learn about obj-c/ios intricacies. e576813

@janicduplessis
Copy link
Contributor Author

@msand Awesome, thanks! I just tested master and everything works fine.

@JNUfeatherwit
Copy link

i have the same problem sometimes,but after reloading the react native app the crash will disappear .I don't know Why?

@iamdurui
Copy link

iamdurui commented Dec 5, 2018

Good news, the fix will make it in the next rn minor react-native-community/react-native-releases#48 (comment)

@janicduplessis this bug(com.facebook.react.bridge.ReadableNativeArray cannot be cast to java.lang.Double ) is solved ? I have the same problem

@iamdurui
Copy link

iamdurui commented Dec 5, 2018

@janicduplessis And my react native version is 0.56.0, if I upgrade the version from my current version to 0.57.4, I can solve this bug(ReadableNativeArray cannot be cast to java.lang.Double)

@msand
Copy link
Collaborator

msand commented Dec 9, 2018

This should be fixed in the latest versions, closing the issue now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants