From 16a6e51045cf45d6f9d929f7ad4b2228f7417942 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 30 Jan 2019 00:11:35 -0800 Subject: [PATCH] Optimize pre-allocation of views Summary: This diff changes the way pre-allocation of views are executed in Fabric. Before this diff the execution of view preallocation was schedulled at the end of the UIThread queue, now the views are pre-allocated in the next "tick" Reviewed By: sahrens Differential Revision: D13857614 fbshipit-source-id: 386bf966d3c8a0d5c0bd626119a92810465aecb7 --- .../react/fabric/FabricUIManager.java | 44 ++++++++++++------- .../mounting/mountitems/BatchMountItem.java | 2 +- .../mountitems/PreAllocateViewMountItem.java | 36 +++++++++++++++ 3 files changed, 65 insertions(+), 17 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/PreAllocateViewMountItem.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 581274f7041..9c3edd31faa 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -29,6 +29,7 @@ import com.facebook.react.fabric.mounting.mountitems.DeleteMountItem; import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem; import com.facebook.react.fabric.mounting.mountitems.InsertMountItem; import com.facebook.react.fabric.mounting.mountitems.MountItem; +import com.facebook.react.fabric.mounting.mountitems.PreAllocateViewMountItem; import com.facebook.react.fabric.mounting.mountitems.RemoveMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem; @@ -49,6 +50,7 @@ import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.ReactConstants; import com.facebook.react.modules.core.ReactChoreographer; +import com.facebook.react.uimanager.IllegalViewOperationException; import com.facebook.react.uimanager.ReactRootViewTagGenerator; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewManagerPropertyUpdater; @@ -94,10 +96,14 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { new ConcurrentHashMap<>(); private final EventBeatManager mEventBeatManager; private final Object mMountItemsLock = new Object(); + private final Object mPreMountItemsLock = new Object(); @GuardedBy("mMountItemsLock") private List mMountItems = new ArrayList<>(); + @GuardedBy("mPreMountItemsLock") + private List mPreMountItems = new ArrayList<>(); + @ThreadConfined(UI) private final DispatchUIFrameCallback mDispatchUIFrameCallback; @@ -177,17 +183,13 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { @DoNotStrip private void preallocateView(final int rootTag, final String componentName) { - UiThreadUtil.runOnUiThread( - new GuardedRunnable(mReactApplicationContext) { - @Override - public void runGuarded() { - ThemedReactContext context = - Assertions.assertNotNull(mReactContextForRootTag.get(rootTag)); - String component = sComponentNames.get(componentName); - Assertions.assertNotNull(component); - mMountingManager.preallocateView(context, component); - } - }); + synchronized (mPreMountItemsLock) { + ThemedReactContext context = + Assertions.assertNotNull(mReactContextForRootTag.get(rootTag)); + String component = sComponentNames.get(componentName); + Assertions.assertNotNull(component); + mPreMountItems.add(new PreAllocateViewMountItem(context, rootTag, component)); + } } @DoNotStrip @@ -286,25 +288,35 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { } try { + List preMountItemsToDispatch; + synchronized (mPreMountItemsLock) { + preMountItemsToDispatch = mPreMountItems; + mPreMountItems = new ArrayList<>(); + } + List mountItemsToDispatch; synchronized (mMountItemsLock) { - if (mMountItems.isEmpty()) { - return; - } mountItemsToDispatch = mMountItems; mMountItems = new ArrayList<>(); } + Systrace.beginSection( + Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, + "FabricUIManager::premountViews (" + preMountItemsToDispatch.size() + " batches)"); + for (MountItem mountItem : preMountItemsToDispatch) { + mountItem.execute(mMountingManager); + } + Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); + Systrace.beginSection( Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricUIManager::mountViews (" + mountItemsToDispatch.size() + " batches)"); for (MountItem mountItem : mountItemsToDispatch) { mountItem.execute(mMountingManager); } - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); } catch (Exception ex) { - FLog.i(ReactConstants.TAG, "Exception thrown when executing UIFrameGuarded", ex); + FLog.e(ReactConstants.TAG, "Exception thrown when executing UIFrameGuarded", ex); mIsMountingEnabled = false; throw ex; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java index 0e02ebe8dcb..252568bef58 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java @@ -6,8 +6,8 @@ */ package com.facebook.react.fabric.mounting.mountitems; -import com.facebook.react.fabric.mounting.MountingManager; import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.fabric.mounting.MountingManager; import com.facebook.systrace.Systrace; /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/PreAllocateViewMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/PreAllocateViewMountItem.java new file mode 100644 index 00000000000..858faf1fe6e --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/PreAllocateViewMountItem.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.MountingManager; +import com.facebook.react.uimanager.ThemedReactContext; + +/** + * {@link MountItem} that is used to pre-allocate views for JS components. + */ +public class PreAllocateViewMountItem implements MountItem { + + private final String mComponent; + private final int mRootTag; + private final ThemedReactContext mContext; + + public PreAllocateViewMountItem(ThemedReactContext context, int rootTag, String component){ + mContext = context; + mComponent = component; + mRootTag = rootTag; + } + + @Override + public void execute(MountingManager mountingManager) { + mountingManager.preallocateView(mContext, mComponent); + } + + @Override + public String toString() { + return "[" + mRootTag + "] - Preallocate " + mComponent; + } +}