From 20c2ae85f02c6f57d73453bf67c5a6254679e8eb Mon Sep 17 00:00:00 2001 From: Aaron Chiu Date: Sun, 7 May 2017 13:45:22 -0700 Subject: [PATCH] allow calling NativeViewHierarchyManager.addRootView() off the UI thread Reviewed By: yungsters, shergin Differential Revision: D4998706 fbshipit-source-id: f95cdcb0d193ffff2dfe39f9523a222d958ba5c6 --- .../uimanager/NativeViewHierarchyManager.java | 51 ++++++++++--------- .../react/uimanager/UIViewOperationQueue.java | 27 ++-------- 2 files changed, 32 insertions(+), 46 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java index a5b157d0f..4a1dc0d9d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -91,7 +91,7 @@ public class NativeViewHierarchyManager { mRootViewManager = manager; } - public final View resolveView(int tag) { + public synchronized final View resolveView(int tag) { View view = mTagsToViews.get(tag); if (view == null) { throw new IllegalViewOperationException("Trying to resolve view with tag " + tag @@ -100,7 +100,7 @@ public class NativeViewHierarchyManager { return view; } - public final ViewManager resolveViewManager(int tag) { + public synchronized final ViewManager resolveViewManager(int tag) { ViewManager viewManager = mTagsToViewManagers.get(tag); if (viewManager == null) { throw new IllegalViewOperationException("ViewManager for tag " + tag + " could not be found"); @@ -116,7 +116,7 @@ public class NativeViewHierarchyManager { mLayoutAnimationEnabled = enabled; } - public void updateProperties(int tag, ReactStylesDiffMap props) { + public synchronized void updateProperties(int tag, ReactStylesDiffMap props) { UiThreadUtil.assertOnUiThread(); try { @@ -128,7 +128,7 @@ public class NativeViewHierarchyManager { } } - public void updateViewExtraData(int tag, Object extraData) { + public synchronized void updateViewExtraData(int tag, Object extraData) { UiThreadUtil.assertOnUiThread(); ViewManager viewManager = resolveViewManager(tag); @@ -136,7 +136,7 @@ public class NativeViewHierarchyManager { viewManager.updateExtraData(viewToUpdate, extraData); } - public void updateLayout( + public synchronized void updateLayout( int parentTag, int tag, int x, @@ -200,7 +200,7 @@ public class NativeViewHierarchyManager { } } - public void createView( + public synchronized void createView( ThemedReactContext themedContext, int tag, String className, @@ -305,11 +305,12 @@ public class NativeViewHierarchyManager { * a view which should be added at the specified index * @param tagsToDelete list of tags corresponding to views that should be removed */ - public void manageChildren( + public synchronized void manageChildren( int tag, @Nullable int[] indicesToRemove, @Nullable ViewAtIndex[] viewsToAdd, @Nullable int[] tagsToDelete) { + UiThreadUtil.assertOnUiThread(); final ViewGroup viewToManage = (ViewGroup) mTagsToViews.get(tag); final ViewGroupManager viewManager = (ViewGroupManager) resolveViewManager(tag); if (viewToManage == null) { @@ -463,9 +464,10 @@ public class NativeViewHierarchyManager { /** * Simplified version of manageChildren that only deals with adding children views */ - public void setChildren( + public synchronized void setChildren( int tag, ReadableArray childrenTags) { + UiThreadUtil.assertOnUiThread(); ViewGroup viewToManage = (ViewGroup) mTagsToViews.get(tag); ViewGroupManager viewManager = (ViewGroupManager) resolveViewManager(tag); @@ -486,21 +488,18 @@ public class NativeViewHierarchyManager { /** * See {@link UIManagerModule#addMeasuredRootView}. - * - * Must be called from the UI thread. */ - public void addRootView( + public synchronized void addRootView( int tag, SizeMonitoringFrameLayout view, ThemedReactContext themedContext) { addRootViewGroup(tag, view, themedContext); } - protected final void addRootViewGroup( + protected synchronized final void addRootViewGroup( int tag, ViewGroup view, ThemedReactContext themedContext) { - UiThreadUtil.assertOnUiThread(); if (view.getId() != View.NO_ID) { throw new IllegalViewOperationException( "Trying to add a root view with an explicit id already set. React Native uses " + @@ -517,7 +516,7 @@ public class NativeViewHierarchyManager { /** * Releases all references to given native View. */ - protected void dropView(View view) { + protected synchronized void dropView(View view) { UiThreadUtil.assertOnUiThread(); if (!mRootTags.get(view.getId())) { // For non-root views we notify viewmanager with {@link ViewManager#onDropInstance} @@ -539,7 +538,7 @@ public class NativeViewHierarchyManager { mTagsToViewManagers.remove(view.getId()); } - public void removeRootView(int rootViewTag) { + public synchronized void removeRootView(int rootViewTag) { UiThreadUtil.assertOnUiThread(); if (!mRootTags.get(rootViewTag)) { SoftAssertions.assertUnreachable( @@ -554,7 +553,7 @@ public class NativeViewHierarchyManager { * Returns true on success, false on failure. If successful, after calling, output buffer will be * {x, y, width, height}. */ - public void measure(int tag, int[] outputBuffer) { + public synchronized void measure(int tag, int[] outputBuffer) { UiThreadUtil.assertOnUiThread(); View v = mTagsToViews.get(tag); if (v == null) { @@ -587,7 +586,7 @@ public class NativeViewHierarchyManager { * @param outputBuffer - output buffer that contains [x,y,width,height] of the view in coordinates * relative to the device window */ - public void measureInWindow(int tag, int[] outputBuffer) { + public synchronized void measureInWindow(int tag, int[] outputBuffer) { UiThreadUtil.assertOnUiThread(); View v = mTagsToViews.get(tag); if (v == null) { @@ -610,7 +609,8 @@ public class NativeViewHierarchyManager { outputBuffer[3] = v.getHeight(); } - public int findTargetTagForTouch(int reactTag, float touchX, float touchY) { + public synchronized int findTargetTagForTouch(int reactTag, float touchX, float touchY) { + UiThreadUtil.assertOnUiThread(); View view = mTagsToViews.get(reactTag); if (view == null) { throw new JSApplicationIllegalArgumentException("Could not find view with tag " + reactTag); @@ -618,7 +618,10 @@ public class NativeViewHierarchyManager { return TouchTargetHelper.findTargetTagForTouch(touchX, touchY, (ViewGroup) view); } - public void setJSResponder(int reactTag, int initialReactTag, boolean blockNativeResponder) { + public synchronized void setJSResponder( + int reactTag, + int initialReactTag, + boolean blockNativeResponder) { if (!blockNativeResponder) { mJSResponderHandler.setJSResponder(initialReactTag, null); return; @@ -652,7 +655,7 @@ public class NativeViewHierarchyManager { mLayoutAnimator.reset(); } - /* package */ void startAnimationForNativeView( + /* package */ synchronized void startAnimationForNativeView( int reactTag, Animation animation, @Nullable final Callback animationCallback) { @@ -691,7 +694,10 @@ public class NativeViewHierarchyManager { } } - public void dispatchCommand(int reactTag, int commandId, @Nullable ReadableArray args) { + public synchronized void dispatchCommand( + int reactTag, + int commandId, + @Nullable ReadableArray args) { UiThreadUtil.assertOnUiThread(); View view = mTagsToViews.get(reactTag); if (view == null) { @@ -712,7 +718,7 @@ public class NativeViewHierarchyManager { * @param success will be called with the position of the selected item as the first argument, or * no arguments if the menu is dismissed */ - public void showPopupMenu(int reactTag, ReadableArray items, Callback success) { + public synchronized void showPopupMenu(int reactTag, ReadableArray items, Callback success) { UiThreadUtil.assertOnUiThread(); View anchor = mTagsToViews.get(reactTag); if (anchor == null) { @@ -780,5 +786,4 @@ public class NativeViewHierarchyManager { } AccessibilityHelper.sendAccessibilityEvent(view, eventType); } - } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java index 7098bf057..b93b82eb3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java @@ -564,29 +564,10 @@ public class UIViewOperationQueue { } public void addRootView( - final int tag, - final SizeMonitoringFrameLayout rootView, - final ThemedReactContext themedRootContext) { - if (UiThreadUtil.isOnUiThread()) { - mNativeViewHierarchyManager.addRootView(tag, rootView, themedRootContext); - } else { - final Semaphore semaphore = new Semaphore(0); - mReactApplicationContext.runOnUiQueueThread( - new Runnable() { - @Override - public void run() { - mNativeViewHierarchyManager.addRootView(tag, rootView, themedRootContext); - semaphore.release(); - } - }); - try { - SoftAssertions.assertCondition( - semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS), - "Timed out adding root view"); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } + final int tag, + final SizeMonitoringFrameLayout rootView, + final ThemedReactContext themedRootContext) { + mNativeViewHierarchyManager.addRootView(tag, rootView, themedRootContext); } /**