Enforced thread safety on UIImplementation methods that mutate the shadowNodeRegistry

This commit is contained in:
Mike Grabowski 2019-04-17 21:32:29 +02:00
parent 54af5b151e
commit f5a31801a0

View File

@ -43,6 +43,7 @@ import javax.annotation.Nullable;
* shadow node hierarchy that is then mapped to a native view hierarchy. * shadow node hierarchy that is then mapped to a native view hierarchy.
*/ */
public class UIImplementation { public class UIImplementation {
protected Object uiImplementationThreadLock = new Object();
protected final EventDispatcher mEventDispatcher; protected final EventDispatcher mEventDispatcher;
protected final ReactApplicationContext mReactContext; protected final ReactApplicationContext mReactContext;
@ -197,6 +198,7 @@ public class UIImplementation {
*/ */
public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> void registerRootView( public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> void registerRootView(
T rootView, int tag, ThemedReactContext context) { T rootView, int tag, ThemedReactContext context) {
synchronized (uiImplementationThreadLock) {
final ReactShadowNode rootCSSNode = createRootShadowNode(); final ReactShadowNode rootCSSNode = createRootShadowNode();
rootCSSNode.setReactTag(tag); rootCSSNode.setReactTag(tag);
rootCSSNode.setThemedContext(context); rootCSSNode.setThemedContext(context);
@ -215,6 +217,7 @@ public class UIImplementation {
// register it within NativeViewHierarchyManager // register it within NativeViewHierarchyManager
mOperationsQueue.addRootView(tag, rootView, context); mOperationsQueue.addRootView(tag, rootView, context);
} }
}
/** /**
* Unregisters a root node with a given tag. * Unregisters a root node with a given tag.
@ -228,8 +231,10 @@ public class UIImplementation {
* Unregisters a root node with a given tag from the shadow node registry * Unregisters a root node with a given tag from the shadow node registry
*/ */
public void removeRootShadowNode(int rootViewTag) { public void removeRootShadowNode(int rootViewTag) {
synchronized (uiImplementationThreadLock) {
mShadowNodeRegistry.removeRootNode(rootViewTag); mShadowNodeRegistry.removeRootNode(rootViewTag);
} }
}
/** /**
* Invoked when native view that corresponds to a root node, or acts as a root view (ie. Modals) * Invoked when native view that corresponds to a root node, or acts as a root view (ie. Modals)
@ -279,6 +284,7 @@ public class UIImplementation {
* Invoked by React to create a new node with a given tag, class name and properties. * Invoked by React to create a new node with a given tag, class name and properties.
*/ */
public void createView(int tag, String className, int rootViewTag, ReadableMap props) { public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
synchronized (uiImplementationThreadLock) {
ReactShadowNode cssNode = createShadowNode(className); ReactShadowNode cssNode = createShadowNode(className);
ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag); ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag);
Assertions.assertNotNull(rootNode, "Root node with tag " + rootViewTag + " doesn't exist"); Assertions.assertNotNull(rootNode, "Root node with tag " + rootViewTag + " doesn't exist");
@ -297,6 +303,7 @@ public class UIImplementation {
handleCreateView(cssNode, rootViewTag, styles); handleCreateView(cssNode, rootViewTag, styles);
} }
}
protected void handleCreateView( protected void handleCreateView(
ReactShadowNode cssNode, ReactShadowNode cssNode,
@ -363,6 +370,7 @@ public class UIImplementation {
@Nullable ReadableArray addChildTags, @Nullable ReadableArray addChildTags,
@Nullable ReadableArray addAtIndices, @Nullable ReadableArray addAtIndices,
@Nullable ReadableArray removeFrom) { @Nullable ReadableArray removeFrom) {
synchronized (uiImplementationThreadLock) {
ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag); ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag);
int numToMove = moveFrom == null ? 0 : moveFrom.size(); int numToMove = moveFrom == null ? 0 : moveFrom.size();
@ -465,6 +473,7 @@ public class UIImplementation {
removeShadowNode(mShadowNodeRegistry.getNode(tagsToDelete[i])); removeShadowNode(mShadowNodeRegistry.getNode(tagsToDelete[i]));
} }
} }
}
/** /**
* An optimized version of manageChildren that is used for initial setting of child views. * An optimized version of manageChildren that is used for initial setting of child views.
@ -476,7 +485,7 @@ public class UIImplementation {
public void setChildren( public void setChildren(
int viewTag, int viewTag,
ReadableArray childrenTags) { ReadableArray childrenTags) {
synchronized (uiImplementationThreadLock) {
ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag); ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag);
for (int i = 0; i < childrenTags.size(); i++) { for (int i = 0; i < childrenTags.size(); i++) {
@ -494,6 +503,7 @@ public class UIImplementation {
childrenTags); childrenTags);
} }
} }
}
/** /**
* Replaces the View specified by oldTag with the View specified by newTag within oldTag's parent. * Replaces the View specified by oldTag with the View specified by newTag within oldTag's parent.