From 46a905b78eb3cffbd72d3256e09900298eee1f44 Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Thu, 17 Nov 2022 17:11:19 +0100 Subject: [PATCH 1/7] feat: make view recycling optional on iOS --- React/Fabric/Mounting/RCTComponentViewProtocol.h | 5 +++++ React/Fabric/Mounting/RCTComponentViewRegistry.mm | 2 +- React/Fabric/Mounting/UIView+ComponentViewProtocol.h | 2 ++ React/Fabric/Mounting/UIView+ComponentViewProtocol.mm | 6 ++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/React/Fabric/Mounting/RCTComponentViewProtocol.h b/React/Fabric/Mounting/RCTComponentViewProtocol.h index 50d7d434f560..483051581fd0 100644 --- a/React/Fabric/Mounting/RCTComponentViewProtocol.h +++ b/React/Fabric/Mounting/RCTComponentViewProtocol.h @@ -111,6 +111,11 @@ typedef NS_OPTIONS(NSInteger, RNComponentViewUpdateMask) { */ - (void)prepareForRecycle; +/* + * Whether the component should go into recycle pool after being destroyed. + */ +- (BOOL)shouldBeRecycled; + /* * Read the last props used to update the view. */ diff --git a/React/Fabric/Mounting/RCTComponentViewRegistry.mm b/React/Fabric/Mounting/RCTComponentViewRegistry.mm index 63bd88e0f763..bf0253104231 100644 --- a/React/Fabric/Mounting/RCTComponentViewRegistry.mm +++ b/React/Fabric/Mounting/RCTComponentViewRegistry.mm @@ -108,7 +108,7 @@ - (void)_enqueueComponentViewWithComponentHandle:(ComponentHandle)componentHandl RCTAssertMainQueue(); auto &recycledViews = _recyclePool[componentHandle]; - if (recycledViews.size() > RCTComponentViewRegistryRecyclePoolMaxSize) { + if (recycledViews.size() > RCTComponentViewRegistryRecyclePoolMaxSize || ![componentViewDescriptor.view shouldBeRecycled]) { return; } diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h index 7b0dd3e96b3b..d43df032ac9c 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h @@ -37,6 +37,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)prepareForRecycle; +- (BOOL)shouldBeRecycled; + - (facebook::react::Props::Shared)props; - (void)setIsJSResponder:(BOOL)isJSResponder; diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm index 4a4bd1eb5d55..381c7d6a2245 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm @@ -129,6 +129,12 @@ - (void)prepareForRecycle // Default implementation does nothing. } +- (BOOL)shouldBeRecycled +{ + // Default implementation always returns `YES`. + return YES; +} + - (facebook::react::Props::Shared)props { RCTAssert(NO, @"props access should be implemented by RCTViewComponentView."); From 1ae82728b915f534f0c0b582ae3407441dd903d3 Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Thu, 20 Jul 2023 19:08:49 +0200 Subject: [PATCH 2/7] fix: move the logic to RCTComponentViewClassDescriptor --- .../RCTComponentViewClassDescriptor.h | 6 ++++ .../Mounting/RCTComponentViewDescriptor.h | 1 + .../Mounting/RCTComponentViewFactory.mm | 35 ++++++++++--------- .../Mounting/RCTComponentViewProtocol.h | 5 --- .../Mounting/RCTComponentViewRegistry.mm | 8 ++--- .../Mounting/UIView+ComponentViewProtocol.h | 2 -- .../Mounting/UIView+ComponentViewProtocol.mm | 6 ---- 7 files changed, 30 insertions(+), 33 deletions(-) diff --git a/React/Fabric/Mounting/RCTComponentViewClassDescriptor.h b/React/Fabric/Mounting/RCTComponentViewClassDescriptor.h index b03a4642a981..a94c8b037837 100644 --- a/React/Fabric/Mounting/RCTComponentViewClassDescriptor.h +++ b/React/Fabric/Mounting/RCTComponentViewClassDescriptor.h @@ -27,6 +27,12 @@ class RCTComponentViewClassDescriptor final { */ bool observesMountingTransactionWillMount{false}; bool observesMountingTransactionDidMount{false}; + + /* + * Indicates that the component should not be recycled + */ + bool shouldBeRecycled{true}; + }; NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/RCTComponentViewDescriptor.h b/React/Fabric/Mounting/RCTComponentViewDescriptor.h index f933f2520b07..0e23d66c3c38 100644 --- a/React/Fabric/Mounting/RCTComponentViewDescriptor.h +++ b/React/Fabric/Mounting/RCTComponentViewDescriptor.h @@ -29,6 +29,7 @@ class RCTComponentViewDescriptor final { */ bool observesMountingTransactionWillMount{false}; bool observesMountingTransactionDidMount{false}; + bool shouldBeRecycled{true}; }; inline bool operator==(RCTComponentViewDescriptor const &lhs, RCTComponentViewDescriptor const &rhs) diff --git a/React/Fabric/Mounting/RCTComponentViewFactory.mm b/React/Fabric/Mounting/RCTComponentViewFactory.mm index 0d8e15cebc2a..8a6a7dd992ea 100644 --- a/React/Fabric/Mounting/RCTComponentViewFactory.mm +++ b/React/Fabric/Mounting/RCTComponentViewFactory.mm @@ -11,8 +11,8 @@ #import #import -#import #import +#import #import #import @@ -23,19 +23,19 @@ #ifdef RN_DISABLE_OSS_PLUGIN_HEADER #import #else -#import "RCTFabricComponentsPlugins.h" +#import #endif -#import "RCTComponentViewClassDescriptor.h" -#import "RCTFabricComponentsPlugins.h" -#import "RCTImageComponentView.h" -#import "RCTLegacyViewManagerInteropComponentView.h" -#import "RCTMountingTransactionObserving.h" -#import "RCTParagraphComponentView.h" -#import "RCTRootComponentView.h" -#import "RCTTextInputComponentView.h" -#import "RCTUnimplementedViewComponentView.h" -#import "RCTViewComponentView.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import #import @@ -61,7 +61,7 @@ @implementation RCTComponentViewFactory { butter::map _componentViewClasses; butter::set _registeredComponentsNames; ComponentDescriptorProviderRegistry _providerRegistry; - butter::shared_mutex _mutex; + std::shared_mutex _mutex; } + (RCTComponentViewFactory *)currentComponentViewFactory @@ -94,6 +94,8 @@ - (RCTComponentViewClassDescriptor)_componentViewClassDescriptorFromClass:(Class (bool)class_respondsToSelector(viewClass, @selector(mountingTransactionWillMount:withSurfaceTelemetry:)), .observesMountingTransactionDidMount = (bool)class_respondsToSelector(viewClass, @selector(mountingTransactionDidMount:withSurfaceTelemetry:)), + .shouldBeRecycled = + (bool)class_respondsToSelector(viewClass, @selector(shouldBeRecycled)), }; #pragma clang diagnostic pop } @@ -155,7 +157,7 @@ - (BOOL)registerComponentIfPossible:(std::string const &)name - (void)registerComponentViewClass:(Class)componentViewClass { RCTAssert(componentViewClass, @"RCTComponentViewFactory: Provided `componentViewClass` is `nil`."); - std::unique_lock lock(_mutex); + std::unique_lock lock(_mutex); auto componentDescriptorProvider = [componentViewClass componentDescriptorProvider]; _componentViewClasses[componentDescriptorProvider.handle] = @@ -177,7 +179,7 @@ - (void)_addDescriptorToProviderRegistry:(ComponentDescriptorProvider const &)pr - (RCTComponentViewDescriptor)createComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle { RCTAssertMainQueue(); - std::shared_lock lock(_mutex); + std::shared_lock lock(_mutex); auto iterator = _componentViewClasses.find(componentHandle); RCTAssert( @@ -192,13 +194,14 @@ - (RCTComponentViewDescriptor)createComponentViewWithComponentHandle:(facebook:: .view = [viewClass new], .observesMountingTransactionWillMount = componentViewClassDescriptor.observesMountingTransactionWillMount, .observesMountingTransactionDidMount = componentViewClassDescriptor.observesMountingTransactionDidMount, + .shouldBeRecycled = componentViewClassDescriptor.shouldBeRecycled, }; } - (facebook::react::ComponentDescriptorRegistry::Shared)createComponentDescriptorRegistryWithParameters: (facebook::react::ComponentDescriptorParameters)parameters { - std::shared_lock lock(_mutex); + std::shared_lock lock(_mutex); return _providerRegistry.createComponentDescriptorRegistry(parameters); } diff --git a/React/Fabric/Mounting/RCTComponentViewProtocol.h b/React/Fabric/Mounting/RCTComponentViewProtocol.h index 483051581fd0..50d7d434f560 100644 --- a/React/Fabric/Mounting/RCTComponentViewProtocol.h +++ b/React/Fabric/Mounting/RCTComponentViewProtocol.h @@ -111,11 +111,6 @@ typedef NS_OPTIONS(NSInteger, RNComponentViewUpdateMask) { */ - (void)prepareForRecycle; -/* - * Whether the component should go into recycle pool after being destroyed. - */ -- (BOOL)shouldBeRecycled; - /* * Read the last props used to update the view. */ diff --git a/React/Fabric/Mounting/RCTComponentViewRegistry.mm b/React/Fabric/Mounting/RCTComponentViewRegistry.mm index bf0253104231..fcc6180a4a9f 100644 --- a/React/Fabric/Mounting/RCTComponentViewRegistry.mm +++ b/React/Fabric/Mounting/RCTComponentViewRegistry.mm @@ -11,9 +11,9 @@ #import #import -#import "RCTImageComponentView.h" -#import "RCTParagraphComponentView.h" -#import "RCTViewComponentView.h" +#import +#import +#import #import @@ -108,7 +108,7 @@ - (void)_enqueueComponentViewWithComponentHandle:(ComponentHandle)componentHandl RCTAssertMainQueue(); auto &recycledViews = _recyclePool[componentHandle]; - if (recycledViews.size() > RCTComponentViewRegistryRecyclePoolMaxSize || ![componentViewDescriptor.view shouldBeRecycled]) { + if (recycledViews.size() > RCTComponentViewRegistryRecyclePoolMaxSize || !componentViewDescriptor.shouldBeRecycled) { return; } diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h index d43df032ac9c..7b0dd3e96b3b 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h @@ -37,8 +37,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)prepareForRecycle; -- (BOOL)shouldBeRecycled; - - (facebook::react::Props::Shared)props; - (void)setIsJSResponder:(BOOL)isJSResponder; diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm index 381c7d6a2245..4a4bd1eb5d55 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm @@ -129,12 +129,6 @@ - (void)prepareForRecycle // Default implementation does nothing. } -- (BOOL)shouldBeRecycled -{ - // Default implementation always returns `YES`. - return YES; -} - - (facebook::react::Props::Shared)props { RCTAssert(NO, @"props access should be implemented by RCTViewComponentView."); From 7feae511ba0c39783e71cbe8923d40a939185f96 Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Mon, 9 Oct 2023 17:17:16 +0200 Subject: [PATCH 3/7] feat: add listener for view mutations --- .../react/bridge/ViewMutationsListener.java | 19 ++ .../mountitems/IntBufferBatchMountItem.java | 167 +++++++++++++----- .../react/uimanager/UIManagerModule.java | 17 ++ 3 files changed, 159 insertions(+), 44 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ViewMutationsListener.java diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ViewMutationsListener.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ViewMutationsListener.java new file mode 100644 index 000000000000..a3e93af907fa --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ViewMutationsListener.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) Meta Platforms, Inc. and 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.bridge; + +import java.util.ArrayList; +import java.util.HashMap; + +public interface ViewMutationsListener { + /** + * Called right before view mutations are dispatched. This is useful if a + * module needs to do something before the views are created/removed. + */ + void willMountViewMutations(ArrayList> mutations); +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java index ad286fcdd172..4b3ed1150955 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java @@ -20,8 +20,13 @@ import com.facebook.react.fabric.mounting.MountingManager; import com.facebook.react.fabric.mounting.SurfaceMountingManager; import com.facebook.react.uimanager.StateWrapper; +import com.facebook.react.uimanager.UIManagerModule; import com.facebook.systrace.Systrace; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + /** * This class represents a batch of {@link MountItem}s, represented directly as int buffers to * remove the need for actual MountItem instances. @@ -117,71 +122,145 @@ public void execute(@NonNull MountingManager mountingManager) { beginMarkers("mountViews"); + ArrayList> mutationsArray = new ArrayList<>(); + + // we put views in the map also for basic operations since tags are only mapped to ViewState + // which are internal. + // In most cases we will need the view to perform an action in the listener int i = 0, j = 0; while (i < mIntBufferLen) { int rawType = mIntBuffer[i++]; int type = rawType & ~INSTRUCTION_FLAG_MULTIPLE; int numInstructions = ((rawType & INSTRUCTION_FLAG_MULTIPLE) != 0 ? mIntBuffer[i++] : 1); for (int k = 0; k < numInstructions; k++) { + HashMap map = new HashMap<>(); if (type == INSTRUCTION_CREATE) { - String componentName = getFabricComponentName((String) mObjBuffer[j++]); - surfaceMountingManager.createView( - componentName, - mIntBuffer[i++], - mObjBuffer[j++], - castToState(mObjBuffer[j++]), - castToEventEmitter(mObjBuffer[j++]), - mIntBuffer[i++] == 1); + map.put("type", "CREATE"); + map.put("componentName", getFabricComponentName((String) mObjBuffer[j++])); + int reactTag = mIntBuffer[i++]; + map.put("reactTag", reactTag); + View view = surfaceMountingManager.getView(reactTag); + map.put("view", view); + map.put("props", mObjBuffer[j++]); + map.put("stateWrapper", castToState(mObjBuffer[j++])); + map.put("eventEmitterWrapper", castToEventEmitter(mObjBuffer[j++])); + map.put("isLayoutable", mIntBuffer[i++] == 1); } else if (type == INSTRUCTION_DELETE) { - surfaceMountingManager.deleteView(mIntBuffer[i++]); + map.put("type", "DELETE"); + int reactTag = mIntBuffer[i++]; + map.put("reactTag", reactTag); + View view = surfaceMountingManager.getView(reactTag); + map.put("view", view); } else if (type == INSTRUCTION_INSERT) { + map.put("type", "INSERT"); int tag = mIntBuffer[i++]; - int parentTag = mIntBuffer[i++]; - surfaceMountingManager.addViewAt(parentTag, tag, mIntBuffer[i++]); + map.put("tag", tag); + View view = surfaceMountingManager.getView(tag); + map.put("view", view); + map.put("parentTag", mIntBuffer[i++]); + map.put("index", mIntBuffer[i++]); } else if (type == INSTRUCTION_REMOVE) { - surfaceMountingManager.removeViewAt(mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]); + map.put("type", "REMOVE"); + int tag = mIntBuffer[i++]; + map.put("tag", tag); + View view = surfaceMountingManager.getView(tag); + map.put("view", view); + map.put("parentTag", mIntBuffer[i++]); + map.put("index", mIntBuffer[i++]); } else if (type == INSTRUCTION_REMOVE_DELETE_TREE) { - surfaceMountingManager.removeDeleteTreeAt( - mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]); + map.put("type", "REMOVE_DELETE_TREE"); + int tag = mIntBuffer[i++]; + map.put("tag", tag); + View view = surfaceMountingManager.getView(tag); + map.put("view", view); + map.put("parentTag", mIntBuffer[i++]); + map.put("index", mIntBuffer[i++]); } else if (type == INSTRUCTION_UPDATE_PROPS) { - surfaceMountingManager.updateProps(mIntBuffer[i++], mObjBuffer[j++]); + map.put("type", "UPDATE_PROPS"); + map.put("reactTag", mIntBuffer[i++]); + map.put("props", mObjBuffer[j++]); } else if (type == INSTRUCTION_UPDATE_STATE) { - surfaceMountingManager.updateState(mIntBuffer[i++], castToState(mObjBuffer[j++])); + map.put("type", "UPDATE_STATE"); + map.put("reactTag", mIntBuffer[i++]); + map.put("stateWrapper", castToState(mObjBuffer[j++])); } else if (type == INSTRUCTION_UPDATE_LAYOUT) { - int reactTag = mIntBuffer[i++]; - int parentTag = mIntBuffer[i++]; - int x = mIntBuffer[i++]; - int y = mIntBuffer[i++]; - int width = mIntBuffer[i++]; - int height = mIntBuffer[i++]; - int displayType = mIntBuffer[i++]; - - surfaceMountingManager.updateLayout( - reactTag, parentTag, x, y, width, height, displayType); - + map.put("type", "UPDATE_LAYOUT"); + map.put("reactTag", mIntBuffer[i++]); + map.put("parentTag", mIntBuffer[i++]); + map.put("x", mIntBuffer[i++]); + map.put("y", mIntBuffer[i++]); + map.put("width", mIntBuffer[i++]); + map.put("height", mIntBuffer[i++]); + map.put("displayType", mIntBuffer[i++]); } else if (type == INSTRUCTION_UPDATE_PADDING) { - surfaceMountingManager.updatePadding( - mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]); + map.put("type", "UPDATE_PADDING"); + map.put("reactTag", mIntBuffer[i++]); + map.put("left", mIntBuffer[i++]); + map.put("top", mIntBuffer[i++]); + map.put("right", mIntBuffer[i++]); + map.put("bottom", mIntBuffer[i++]); } else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) { - int reactTag = mIntBuffer[i++]; - int overflowInsetLeft = mIntBuffer[i++]; - int overflowInsetTop = mIntBuffer[i++]; - int overflowInsetRight = mIntBuffer[i++]; - int overflowInsetBottom = mIntBuffer[i++]; - - surfaceMountingManager.updateOverflowInset( - reactTag, - overflowInsetLeft, - overflowInsetTop, - overflowInsetRight, - overflowInsetBottom); + map.put("type", "UPDATE_OVERFLOW_INSET"); + map.put("reactTag", mIntBuffer[i++]); + map.put("overflowInsetLeft", mIntBuffer[i++]); + map.put("overflowInsetTop", mIntBuffer[i++]); + map.put("overflowInsetRight", mIntBuffer[i++]); + map.put("overflowInsetBottom", mIntBuffer[i++]); } else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) { - surfaceMountingManager.updateEventEmitter( - mIntBuffer[i++], castToEventEmitter(mObjBuffer[j++])); + map.put("type", "UPDATE_EVENT_EMITTER"); + map.put("reactTag", mIntBuffer[i++]); + map.put("eventEmitter", castToEventEmitter(mObjBuffer[j++])); } else { throw new IllegalArgumentException( - "Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i); + "Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i); } + mutationsArray.add(map); + } + } + + surfaceMountingManager.getContext().getNativeModule(UIManagerModule.class).viewMutationsWillMount(mutationsArray); + + for (HashMap elem: mutationsArray) { + if ("CREATE".equals(elem.get("type"))) { + surfaceMountingManager.createView( + (String)elem.get("componentName"), + (int)elem.get("reactTag"), + elem.get("props"), + (StateWrapper)elem.get("stateWrapper"), + (EventEmitterWrapper)elem.get("eventEmitterWrapper"), + (boolean)elem.get("isLayoutable")); + } else if ("DELETE".equals(elem.get("type"))) { + surfaceMountingManager.deleteView((int)elem.get("reactTag")); + } else if ("INSERT".equals(elem.get("type"))) { + surfaceMountingManager.addViewAt((int)elem.get("parentTag"), (int)elem.get("tag"), (int)elem.get("index")); + } else if ("REMOVE".equals(elem.get("type"))) { + surfaceMountingManager.removeViewAt((int)elem.get("tag"), (int)elem.get("parentTag"), (int)elem.get("index")); + } else if ("REMOVE_DELETE_TREE".equals(elem.get("type"))) { + surfaceMountingManager.removeDeleteTreeAt( + (int)elem.get("tag"), (int)elem.get("parentTag"), (int)elem.get("index")); + } else if ("UPDATE_PROPS".equals(elem.get("type"))) { + surfaceMountingManager.updateProps((int)elem.get("reactTag"), elem.get("props")); + } else if ("UPDATE_STATE".equals(elem.get("type"))) { + surfaceMountingManager.updateState((int)elem.get("reactTag"), (StateWrapper) elem.get("stateWrapper")); + } else if ("UPDATE_LAYOUT".equals(elem.get("type"))) { + surfaceMountingManager.updateLayout( + (int)elem.get("reactTag"), (int)elem.get("parentTag"), + (int)elem.get("x"), (int)elem.get("y"), (int)elem.get("width"), + (int)elem.get("height"), (int)elem.get("displayType")); + + } else if ("UPDATE_PADDING".equals(elem.get("type"))) { + surfaceMountingManager.updatePadding( + (int)elem.get("reactTag"), (int)elem.get("left"), (int)elem.get("top"), (int)elem.get("right"), (int)elem.get("bottom")); + } else if ("UPDATE_OVERFLOW_INSET".equals(elem.get("type"))) { + surfaceMountingManager.updateOverflowInset( + (int)elem.get("reactTag"), (int)elem.get("overflowInsetLeft"), (int)elem.get("overflowInsetTop") + , (int)elem.get("overflowInsetRight"), (int)elem.get("overflowInsetBottom")); + } else if ("UPDATE_EVENT_EMITTER".equals(elem.get("type"))) { + surfaceMountingManager.updateEventEmitter( + (int)elem.get("reactTag"), (EventEmitterWrapper) elem.get("eventEmitter")); + } else { + throw new IllegalArgumentException( + "Invalid type argument to IntBufferBatchMountItem: " + elem.get("type")); } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 8ef20ad609a5..18457d278ffd 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -37,6 +37,7 @@ import com.facebook.react.bridge.UIManagerListener; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.ViewMutationsListener; import com.facebook.react.common.MapBuilder; import com.facebook.react.common.ReactConstants; import com.facebook.react.module.annotations.ReactModule; @@ -48,6 +49,7 @@ import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; @@ -105,6 +107,7 @@ public interface CustomEventNamesResolver { private final UIImplementation mUIImplementation; private final MemoryTrimCallback mMemoryTrimCallback = new MemoryTrimCallback(); private final List mListeners = new ArrayList<>(); + private final CopyOnWriteArrayList mViewMutationsListeners = new CopyOnWriteArrayList<>(); private final CopyOnWriteArrayList mUIManagerListeners = new CopyOnWriteArrayList<>(); @@ -793,6 +796,20 @@ public void removeUIManagerEventListener(UIManagerListener listener) { mUIManagerListeners.remove(listener); } + public void addViewMutationsListener(ViewMutationsListener listener) { + mViewMutationsListeners.add(listener); + } + + public void removeViewMutationsListener(ViewMutationsListener listener) { + mViewMutationsListeners.remove(listener); + } + + public void viewMutationsWillMount(ArrayList> mutations) { + for (ViewMutationsListener listener : mViewMutationsListeners) { + listener.willMountViewMutations(mutations); + } + } + /** * Given a reactTag from a component, find its root node tag, if possible. Otherwise, this will * return 0. If the reactTag belongs to a root node, this will return the same reactTag. From a01c12ea33913294ae8c8f454ca8dee508f4bdbd Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Mon, 9 Oct 2023 18:23:46 +0200 Subject: [PATCH 4/7] chore: revert changes from main --- .../React/Fabric/Mounting/RCTComponentViewClassDescriptor.h | 6 ------ .../React/Fabric/Mounting/RCTComponentViewDescriptor.h | 1 - .../React/Fabric/Mounting/RCTComponentViewFactory.mm | 3 --- .../React/Fabric/Mounting/RCTComponentViewRegistry.mm | 2 +- 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/RCTComponentViewClassDescriptor.h b/packages/react-native/React/Fabric/Mounting/RCTComponentViewClassDescriptor.h index a94c8b037837..b03a4642a981 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTComponentViewClassDescriptor.h +++ b/packages/react-native/React/Fabric/Mounting/RCTComponentViewClassDescriptor.h @@ -27,12 +27,6 @@ class RCTComponentViewClassDescriptor final { */ bool observesMountingTransactionWillMount{false}; bool observesMountingTransactionDidMount{false}; - - /* - * Indicates that the component should not be recycled - */ - bool shouldBeRecycled{true}; - }; NS_ASSUME_NONNULL_END diff --git a/packages/react-native/React/Fabric/Mounting/RCTComponentViewDescriptor.h b/packages/react-native/React/Fabric/Mounting/RCTComponentViewDescriptor.h index fd1c4b9feb0c..3ca65d18fcb1 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTComponentViewDescriptor.h +++ b/packages/react-native/React/Fabric/Mounting/RCTComponentViewDescriptor.h @@ -29,7 +29,6 @@ class RCTComponentViewDescriptor final { */ bool observesMountingTransactionWillMount{false}; bool observesMountingTransactionDidMount{false}; - bool shouldBeRecycled{true}; }; inline bool operator==(const RCTComponentViewDescriptor &lhs, const RCTComponentViewDescriptor &rhs) diff --git a/packages/react-native/React/Fabric/Mounting/RCTComponentViewFactory.mm b/packages/react-native/React/Fabric/Mounting/RCTComponentViewFactory.mm index 72657ab98dca..0b15d7112a85 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTComponentViewFactory.mm +++ b/packages/react-native/React/Fabric/Mounting/RCTComponentViewFactory.mm @@ -95,8 +95,6 @@ - (RCTComponentViewClassDescriptor)_componentViewClassDescriptorFromClass:(Class (bool)class_respondsToSelector(viewClass, @selector(mountingTransactionWillMount:withSurfaceTelemetry:)), .observesMountingTransactionDidMount = (bool)class_respondsToSelector(viewClass, @selector(mountingTransactionDidMount:withSurfaceTelemetry:)), - .shouldBeRecycled = - (bool)class_respondsToSelector(viewClass, @selector(shouldBeRecycled)), }; #pragma clang diagnostic pop } @@ -212,7 +210,6 @@ - (RCTComponentViewDescriptor)createComponentViewWithComponentHandle:(facebook:: .view = [viewClass new], .observesMountingTransactionWillMount = componentViewClassDescriptor.observesMountingTransactionWillMount, .observesMountingTransactionDidMount = componentViewClassDescriptor.observesMountingTransactionDidMount, - .shouldBeRecycled = componentViewClassDescriptor.shouldBeRecycled, }; } diff --git a/packages/react-native/React/Fabric/Mounting/RCTComponentViewRegistry.mm b/packages/react-native/React/Fabric/Mounting/RCTComponentViewRegistry.mm index 74ebc3160ea4..e78e8ae53342 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTComponentViewRegistry.mm +++ b/packages/react-native/React/Fabric/Mounting/RCTComponentViewRegistry.mm @@ -107,7 +107,7 @@ - (void)_enqueueComponentViewWithComponentHandle:(ComponentHandle)componentHandl RCTAssertMainQueue(); auto &recycledViews = _recyclePool[componentHandle]; - if (recycledViews.size() > RCTComponentViewRegistryRecyclePoolMaxSize || !componentViewDescriptor.shouldBeRecycled) { + if (recycledViews.size() > RCTComponentViewRegistryRecyclePoolMaxSize) { return; } From 746b0bc49d9e1b7eefb2c1894fd1a2db5d7ee62e Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Tue, 10 Oct 2023 16:05:58 +0200 Subject: [PATCH 5/7] fix: class approach for better performance --- .../react/bridge/ViewMutationsListener.java | 5 +- .../mounting/mountitems/InstructionType.java | 8 + .../mountitems/IntBufferBatchMountItem.java | 290 +++++++++++------- .../mountitems/IntBufferMountItem.java | 30 ++ .../mountitems/IntBufferMountItemCreate.java | 46 +++ .../mountitems/IntBufferMountItemDelete.java | 13 + .../mountitems/IntBufferMountItemInsert.java | 32 ++ .../mountitems/IntBufferMountItemRemove.java | 32 ++ .../IntBufferMountItemRemoveDeleteTree.java | 32 ++ .../IntBufferMountItemUpdateEventEmitter.java | 22 ++ .../IntBufferMountItemUpdateLayout.java | 57 ++++ ...IntBufferMountItemUpdateOverflowInset.java | 39 +++ .../IntBufferMountItemUpdatePadding.java | 40 +++ .../IntBufferMountItemUpdateProps.java | 20 ++ .../IntBufferMountItemUpdateState.java | 22 ++ .../react/uimanager/UIManagerModule.java | 3 +- 16 files changed, 584 insertions(+), 107 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InstructionType.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItem.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemCreate.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemDelete.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemInsert.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemRemove.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemRemoveDeleteTree.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateEventEmitter.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateLayout.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateOverflowInset.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdatePadding.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateProps.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateState.java diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ViewMutationsListener.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ViewMutationsListener.java index a3e93af907fa..e723ee2138c1 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ViewMutationsListener.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ViewMutationsListener.java @@ -7,13 +7,14 @@ package com.facebook.react.bridge; +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; + import java.util.ArrayList; -import java.util.HashMap; public interface ViewMutationsListener { /** * Called right before view mutations are dispatched. This is useful if a * module needs to do something before the views are created/removed. */ - void willMountViewMutations(ArrayList> mutations); + void willMountViewMutations(ArrayList mutations); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InstructionType.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InstructionType.java new file mode 100644 index 000000000000..d2bc6e8b2b77 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InstructionType.java @@ -0,0 +1,8 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; + +public enum InstructionType { + CREATE, DELETE, INSERT, REMOVE, UPDATE_PROPS, UPDATE_STATE, UPDATE_LAYOUT, UPDATE_EVENT_EMITTER, + UPDATE_PADDING, UPDATE_OVERFLOW_INSET, REMOVE_DELETE_TREE +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java index 4b3ed1150955..4d10fad5ca72 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java @@ -122,7 +122,7 @@ public void execute(@NonNull MountingManager mountingManager) { beginMarkers("mountViews"); - ArrayList> mutationsArray = new ArrayList<>(); + ArrayList mutationsArray = new ArrayList<>(); // we put views in the map also for basic operations since tags are only mapped to ViewState // which are internal. @@ -133,134 +133,216 @@ public void execute(@NonNull MountingManager mountingManager) { int type = rawType & ~INSTRUCTION_FLAG_MULTIPLE; int numInstructions = ((rawType & INSTRUCTION_FLAG_MULTIPLE) != 0 ? mIntBuffer[i++] : 1); for (int k = 0; k < numInstructions; k++) { - HashMap map = new HashMap<>(); + IntBufferMountItem item; if (type == INSTRUCTION_CREATE) { - map.put("type", "CREATE"); - map.put("componentName", getFabricComponentName((String) mObjBuffer[j++])); + String componentName = getFabricComponentName((String) mObjBuffer[j++]); int reactTag = mIntBuffer[i++]; - map.put("reactTag", reactTag); - View view = surfaceMountingManager.getView(reactTag); - map.put("view", view); - map.put("props", mObjBuffer[j++]); - map.put("stateWrapper", castToState(mObjBuffer[j++])); - map.put("eventEmitterWrapper", castToEventEmitter(mObjBuffer[j++])); - map.put("isLayoutable", mIntBuffer[i++] == 1); + View view = null; + if (surfaceMountingManager.getViewExists(reactTag)) { + view = surfaceMountingManager.getView(reactTag); + } + Object props = mObjBuffer[j++]; + StateWrapper stateWrapper = castToState(mObjBuffer[j++]); + EventEmitterWrapper eventEmitterWrapper = castToEventEmitter(mObjBuffer[j++]); + boolean isLayoutable = mIntBuffer[i++] == 1; + item = new IntBufferMountItemCreate(reactTag, + view, componentName, props, stateWrapper, eventEmitterWrapper, isLayoutable); + } else if (type == INSTRUCTION_DELETE) { - map.put("type", "DELETE"); int reactTag = mIntBuffer[i++]; - map.put("reactTag", reactTag); - View view = surfaceMountingManager.getView(reactTag); - map.put("view", view); + item = new IntBufferMountItemDelete(reactTag, null); } else if (type == INSTRUCTION_INSERT) { - map.put("type", "INSERT"); int tag = mIntBuffer[i++]; - map.put("tag", tag); - View view = surfaceMountingManager.getView(tag); - map.put("view", view); - map.put("parentTag", mIntBuffer[i++]); - map.put("index", mIntBuffer[i++]); + View view = null; + if (surfaceMountingManager.getViewExists(tag)) { + view = surfaceMountingManager.getView(tag); + } + int parentTag = mIntBuffer[i++]; + View parentView = null; + if (surfaceMountingManager.getViewExists(parentTag)) { + parentView = surfaceMountingManager.getView(parentTag); + } + int index = mIntBuffer[i++]; + item = new IntBufferMountItemInsert(tag, view, parentTag, parentView, index); } else if (type == INSTRUCTION_REMOVE) { - map.put("type", "REMOVE"); int tag = mIntBuffer[i++]; - map.put("tag", tag); - View view = surfaceMountingManager.getView(tag); - map.put("view", view); - map.put("parentTag", mIntBuffer[i++]); - map.put("index", mIntBuffer[i++]); + View view = null; + if (surfaceMountingManager.getViewExists(tag)) { + view = surfaceMountingManager.getView(tag); + } + int parentTag = mIntBuffer[i++]; + View parentView = null; + if (surfaceMountingManager.getViewExists(parentTag)) { + parentView = surfaceMountingManager.getView(parentTag); + } + int index = mIntBuffer[i++]; + item = new IntBufferMountItemRemove(tag, view, parentTag, parentView, index); } else if (type == INSTRUCTION_REMOVE_DELETE_TREE) { - map.put("type", "REMOVE_DELETE_TREE"); int tag = mIntBuffer[i++]; - map.put("tag", tag); - View view = surfaceMountingManager.getView(tag); - map.put("view", view); - map.put("parentTag", mIntBuffer[i++]); - map.put("index", mIntBuffer[i++]); + View view = null; + if (surfaceMountingManager.getViewExists(tag)) { + view = surfaceMountingManager.getView(tag); + } + int parentTag = mIntBuffer[i++]; + View parentView = null; + if (surfaceMountingManager.getViewExists(parentTag)) { + parentView = surfaceMountingManager.getView(parentTag); + } + int index = mIntBuffer[i++]; + item = new IntBufferMountItemRemoveDeleteTree(tag, view, parentTag, parentView, index); } else if (type == INSTRUCTION_UPDATE_PROPS) { - map.put("type", "UPDATE_PROPS"); - map.put("reactTag", mIntBuffer[i++]); - map.put("props", mObjBuffer[j++]); + int reactTag = mIntBuffer[i++]; + View view = null; + if (surfaceMountingManager.getViewExists(reactTag)) { + view = surfaceMountingManager.getView(reactTag); + } + Object props = mObjBuffer[j++]; + item = new IntBufferMountItemUpdateProps(reactTag, view, props); } else if (type == INSTRUCTION_UPDATE_STATE) { - map.put("type", "UPDATE_STATE"); - map.put("reactTag", mIntBuffer[i++]); - map.put("stateWrapper", castToState(mObjBuffer[j++])); + int reactTag = mIntBuffer[i++]; + View view = null; + if (surfaceMountingManager.getViewExists(reactTag)) { + view = surfaceMountingManager.getView(reactTag); + } + StateWrapper stateWrapper = castToState(mObjBuffer[j++]); + item = new IntBufferMountItemUpdateState(reactTag, view, stateWrapper); } else if (type == INSTRUCTION_UPDATE_LAYOUT) { - map.put("type", "UPDATE_LAYOUT"); - map.put("reactTag", mIntBuffer[i++]); - map.put("parentTag", mIntBuffer[i++]); - map.put("x", mIntBuffer[i++]); - map.put("y", mIntBuffer[i++]); - map.put("width", mIntBuffer[i++]); - map.put("height", mIntBuffer[i++]); - map.put("displayType", mIntBuffer[i++]); + int reactTag = mIntBuffer[i++]; + View view = null; + if (surfaceMountingManager.getViewExists(reactTag)) { + view = surfaceMountingManager.getView(reactTag); + } + int parentTag = mIntBuffer[i++]; + View parentView = null; + if (surfaceMountingManager.getViewExists(parentTag)) { + parentView = surfaceMountingManager.getView(parentTag); + } + int x = mIntBuffer[i++]; + int y = mIntBuffer[i++]; + int width = mIntBuffer[i++]; + int height = mIntBuffer[i++]; + int displayType = mIntBuffer[i++]; + item = new IntBufferMountItemUpdateLayout(reactTag, view, parentTag, parentView, x, y, + width, height, displayType); } else if (type == INSTRUCTION_UPDATE_PADDING) { - map.put("type", "UPDATE_PADDING"); - map.put("reactTag", mIntBuffer[i++]); - map.put("left", mIntBuffer[i++]); - map.put("top", mIntBuffer[i++]); - map.put("right", mIntBuffer[i++]); - map.put("bottom", mIntBuffer[i++]); + int reactTag = mIntBuffer[i++]; + View view = null; + if (surfaceMountingManager.getViewExists(reactTag)) { + view = surfaceMountingManager.getView(reactTag); + } + int left = mIntBuffer[i++]; + int top = mIntBuffer[i++]; + int right = mIntBuffer[i++]; + int bottom = mIntBuffer[i++]; + item = new IntBufferMountItemUpdatePadding(reactTag, view, left, top, right, bottom); } else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) { - map.put("type", "UPDATE_OVERFLOW_INSET"); - map.put("reactTag", mIntBuffer[i++]); - map.put("overflowInsetLeft", mIntBuffer[i++]); - map.put("overflowInsetTop", mIntBuffer[i++]); - map.put("overflowInsetRight", mIntBuffer[i++]); - map.put("overflowInsetBottom", mIntBuffer[i++]); + int reactTag = mIntBuffer[i++]; + View view = null; + if (surfaceMountingManager.getViewExists(reactTag)) { + view = surfaceMountingManager.getView(reactTag); + } + int overflowInsetLeft = mIntBuffer[i++]; + int overflowInsetTop = mIntBuffer[i++]; + int overflowInsetRight = mIntBuffer[i++]; + int overflowInsetBottom = mIntBuffer[i++]; + item = new IntBufferMountItemUpdateOverflowInset(reactTag, view, overflowInsetLeft, + overflowInsetTop, overflowInsetRight, overflowInsetBottom); } else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) { - map.put("type", "UPDATE_EVENT_EMITTER"); - map.put("reactTag", mIntBuffer[i++]); - map.put("eventEmitter", castToEventEmitter(mObjBuffer[j++])); + int reactTag = mIntBuffer[i++]; + EventEmitterWrapper eventEmitterWrapper = castToEventEmitter(mObjBuffer[j++]); + item = new IntBufferMountItemUpdateEventEmitter(reactTag, null, eventEmitterWrapper); } else { throw new IllegalArgumentException( "Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i); } - mutationsArray.add(map); + mutationsArray.add(item); } } surfaceMountingManager.getContext().getNativeModule(UIManagerModule.class).viewMutationsWillMount(mutationsArray); - for (HashMap elem: mutationsArray) { - if ("CREATE".equals(elem.get("type"))) { - surfaceMountingManager.createView( - (String)elem.get("componentName"), - (int)elem.get("reactTag"), - elem.get("props"), - (StateWrapper)elem.get("stateWrapper"), - (EventEmitterWrapper)elem.get("eventEmitterWrapper"), - (boolean)elem.get("isLayoutable")); - } else if ("DELETE".equals(elem.get("type"))) { - surfaceMountingManager.deleteView((int)elem.get("reactTag")); - } else if ("INSERT".equals(elem.get("type"))) { - surfaceMountingManager.addViewAt((int)elem.get("parentTag"), (int)elem.get("tag"), (int)elem.get("index")); - } else if ("REMOVE".equals(elem.get("type"))) { - surfaceMountingManager.removeViewAt((int)elem.get("tag"), (int)elem.get("parentTag"), (int)elem.get("index")); - } else if ("REMOVE_DELETE_TREE".equals(elem.get("type"))) { - surfaceMountingManager.removeDeleteTreeAt( - (int)elem.get("tag"), (int)elem.get("parentTag"), (int)elem.get("index")); - } else if ("UPDATE_PROPS".equals(elem.get("type"))) { - surfaceMountingManager.updateProps((int)elem.get("reactTag"), elem.get("props")); - } else if ("UPDATE_STATE".equals(elem.get("type"))) { - surfaceMountingManager.updateState((int)elem.get("reactTag"), (StateWrapper) elem.get("stateWrapper")); - } else if ("UPDATE_LAYOUT".equals(elem.get("type"))) { - surfaceMountingManager.updateLayout( - (int)elem.get("reactTag"), (int)elem.get("parentTag"), - (int)elem.get("x"), (int)elem.get("y"), (int)elem.get("width"), - (int)elem.get("height"), (int)elem.get("displayType")); - - } else if ("UPDATE_PADDING".equals(elem.get("type"))) { - surfaceMountingManager.updatePadding( - (int)elem.get("reactTag"), (int)elem.get("left"), (int)elem.get("top"), (int)elem.get("right"), (int)elem.get("bottom")); - } else if ("UPDATE_OVERFLOW_INSET".equals(elem.get("type"))) { - surfaceMountingManager.updateOverflowInset( - (int)elem.get("reactTag"), (int)elem.get("overflowInsetLeft"), (int)elem.get("overflowInsetTop") - , (int)elem.get("overflowInsetRight"), (int)elem.get("overflowInsetBottom")); - } else if ("UPDATE_EVENT_EMITTER".equals(elem.get("type"))) { - surfaceMountingManager.updateEventEmitter( - (int)elem.get("reactTag"), (EventEmitterWrapper) elem.get("eventEmitter")); - } else { - throw new IllegalArgumentException( - "Invalid type argument to IntBufferBatchMountItem: " + elem.get("type")); + for (IntBufferMountItem elem: mutationsArray) { + switch (elem.getInstructionType()) { + case CREATE: { + IntBufferMountItemCreate createElem = (IntBufferMountItemCreate) elem; + surfaceMountingManager.createView( + createElem.getComponentName(), + createElem.getReactTag(), + createElem.getProps(), + createElem.getStateWrapper(), + createElem.getEventEmitterWrapper(), + createElem.isLayoutable()); + break; + } + case DELETE: { + IntBufferMountItemDelete deleteElem = (IntBufferMountItemDelete) elem; + surfaceMountingManager.deleteView(deleteElem.getReactTag()); + break; + } + case INSERT: { + IntBufferMountItemInsert insertElem = (IntBufferMountItemInsert) elem; + surfaceMountingManager.addViewAt(insertElem.getParentTag(), insertElem.getReactTag(), insertElem.getIndex()); + break; + } + case REMOVE: { + IntBufferMountItemRemove removeElem = (IntBufferMountItemRemove) elem; + surfaceMountingManager.removeViewAt(removeElem.getReactTag(), removeElem.getParentTag(), removeElem.getIndex()); + break; + } + case REMOVE_DELETE_TREE: { + IntBufferMountItemRemoveDeleteTree removeDeleteTreeElem = (IntBufferMountItemRemoveDeleteTree) elem; + surfaceMountingManager.removeDeleteTreeAt(removeDeleteTreeElem.getReactTag(), + removeDeleteTreeElem.getParentTag(), removeDeleteTreeElem.getIndex()); + break; + } + case UPDATE_PROPS: { + IntBufferMountItemUpdateProps updatePropsElem = (IntBufferMountItemUpdateProps) elem; + surfaceMountingManager.updateProps(updatePropsElem.getReactTag(), + updatePropsElem.getProps()); + break; + } + case UPDATE_STATE: { + IntBufferMountItemUpdateState updateStateElem = (IntBufferMountItemUpdateState) elem; + surfaceMountingManager.updateState(updateStateElem.getReactTag(), + updateStateElem.getStateWrapper()); + break; + } + case UPDATE_LAYOUT: { + IntBufferMountItemUpdateLayout updateLayoutElem = (IntBufferMountItemUpdateLayout) elem; + surfaceMountingManager.updateLayout(updateLayoutElem.getReactTag(), + updateLayoutElem.getParentTag(), updateLayoutElem.getX(), updateLayoutElem.getY(), + updateLayoutElem.getWidth(), updateLayoutElem.getHeight(), + updateLayoutElem.getDisplayType()); + break; + } + case UPDATE_PADDING: { + IntBufferMountItemUpdatePadding updatePaddingElem = (IntBufferMountItemUpdatePadding) elem; + surfaceMountingManager.updatePadding(updatePaddingElem.getReactTag(), + updatePaddingElem.getLeft(), updatePaddingElem.getTop(), + updatePaddingElem.getRight(), updatePaddingElem.getBottom()); + break; + } + case UPDATE_OVERFLOW_INSET: { + IntBufferMountItemUpdateOverflowInset updateOverflowInsetElem = + (IntBufferMountItemUpdateOverflowInset) elem; + surfaceMountingManager.updateOverflowInset(updateOverflowInsetElem.getReactTag(), + updateOverflowInsetElem.getOverflowInsetLeft(), + updateOverflowInsetElem.getOverflowInsetTop(), + updateOverflowInsetElem.getOverflowInsetRight(), + updateOverflowInsetElem.getOverflowInsetBottom()); + break; + } + case UPDATE_EVENT_EMITTER: { + IntBufferMountItemUpdateEventEmitter updateEventEmitterElem = + (IntBufferMountItemUpdateEventEmitter) elem; + surfaceMountingManager.updateEventEmitter(updateEventEmitterElem.getReactTag(), + updateEventEmitterElem.getEventEmitterWrapper()); + break; + } + default: { + throw new IllegalArgumentException( + "Invalid type argument to IntBufferBatchMountItem: " + elem.getInstructionType()); + } } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItem.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItem.java new file mode 100644 index 000000000000..15acb2e7625b --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItem.java @@ -0,0 +1,30 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; + +import android.view.View; + +public abstract class IntBufferMountItem { + private final InstructionType instructionType; + private final int reactTag; + private final View view; + + public IntBufferMountItem(InstructionType instructionType, int reactTag, View view) { + this.instructionType = instructionType; + this.reactTag = reactTag; + this.view = view; + } + + public InstructionType getInstructionType() { + return instructionType; + } + + public int getReactTag() { + return reactTag; + } + + public View getView() { + return view; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemCreate.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemCreate.java new file mode 100644 index 000000000000..c46b51abe73c --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemCreate.java @@ -0,0 +1,46 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.InstructionType; +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.uimanager.StateWrapper; +import com.facebook.react.fabric.events.EventEmitterWrapper; + +import android.view.View; + +public class IntBufferMountItemCreate extends IntBufferMountItem { + + private final String componentName; + private final Object props; + private final StateWrapper stateWrapper; + private final EventEmitterWrapper eventEmitterWrapper; + private final boolean isLayoutable; + + public IntBufferMountItemCreate(int reactTag, View view, String componentName, Object props, StateWrapper stateWrapper, EventEmitterWrapper eventEmitterWrapper, boolean isLayoutable) { + super(InstructionType.CREATE, reactTag, view); + this.componentName = componentName; + this.props = props; + this.stateWrapper = stateWrapper; + this.eventEmitterWrapper = eventEmitterWrapper; + this.isLayoutable = isLayoutable; + } + + public String getComponentName() { + return componentName; + } + + public Object getProps() { + return props; + } + + public StateWrapper getStateWrapper() { + return stateWrapper; + } + + public EventEmitterWrapper getEventEmitterWrapper() { + return eventEmitterWrapper; + } + + public boolean isLayoutable() { + return isLayoutable; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemDelete.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemDelete.java new file mode 100644 index 000000000000..d5fc005c55fc --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemDelete.java @@ -0,0 +1,13 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; + +import android.view.View; + +public class IntBufferMountItemDelete extends IntBufferMountItem { + + public IntBufferMountItemDelete(int reactTag, View view) { + super(InstructionType.DELETE, reactTag, view); + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemInsert.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemInsert.java new file mode 100644 index 000000000000..e4e6ff50acc6 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemInsert.java @@ -0,0 +1,32 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; + +import android.view.View; + +public class IntBufferMountItemInsert extends IntBufferMountItem { + + private int parentTag; + private View parentView; + private int index; + + public IntBufferMountItemInsert(int reactTag, View view, int parentTag, View parentView, int index) { + super(InstructionType.INSERT, reactTag, view); + this.parentTag = parentTag; + this.parentView = parentView; + this.index = index; + } + + public int getParentTag() { + return parentTag; + } + + public View getParentView() { + return parentView; + } + + public int getIndex() { + return index; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemRemove.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemRemove.java new file mode 100644 index 000000000000..4f59f67f0921 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemRemove.java @@ -0,0 +1,32 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; + +import android.view.View; + +public class IntBufferMountItemRemove extends IntBufferMountItem { + + private int parentTag; + private View parentView; + private int index; + + public IntBufferMountItemRemove(int reactTag, View view, int parentTag, View parentView, int index) { + super(InstructionType.REMOVE, reactTag, view); + this.parentTag = parentTag; + this.parentView = parentView; + this.index = index; + } + + public int getParentTag() { + return parentTag; + } + + public View getParentView() { + return parentView; + } + + public int getIndex() { + return index; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemRemoveDeleteTree.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemRemoveDeleteTree.java new file mode 100644 index 000000000000..48a3a0429655 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemRemoveDeleteTree.java @@ -0,0 +1,32 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; + +import android.view.View; + +public class IntBufferMountItemRemoveDeleteTree extends IntBufferMountItem { + + private int parentTag; + private View parentView; + private int index; + + public IntBufferMountItemRemoveDeleteTree(int reactTag, View view, int parentTag, View parentView, int index) { + super(InstructionType.REMOVE_DELETE_TREE, reactTag, view); + this.parentTag = parentTag; + this.parentView = parentView; + this.index = index; + } + + public int getParentTag() { + return parentTag; + } + + public View getParentView() { + return parentView; + } + + public int getIndex() { + return index; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateEventEmitter.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateEventEmitter.java new file mode 100644 index 000000000000..30f896ab0e0b --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateEventEmitter.java @@ -0,0 +1,22 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; +import com.facebook.react.fabric.events.EventEmitterWrapper; + +import android.view.View; + +public class IntBufferMountItemUpdateEventEmitter extends IntBufferMountItem { + + private final EventEmitterWrapper eventEmitterWrapper; + + public IntBufferMountItemUpdateEventEmitter(int reactTag, View view, + EventEmitterWrapper eventEmitterWrapper) { + super(InstructionType.UPDATE_EVENT_EMITTER, reactTag, view); + this.eventEmitterWrapper = eventEmitterWrapper; + } + + public EventEmitterWrapper getEventEmitterWrapper() { + return eventEmitterWrapper; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateLayout.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateLayout.java new file mode 100644 index 000000000000..a166f028fc11 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateLayout.java @@ -0,0 +1,57 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; + +import android.view.View; + +public class IntBufferMountItemUpdateLayout extends IntBufferMountItem { + + private int parentTag; + private View parentView; + private int x; + private int y; + private int width; + private int height; + private int displayType; + + public IntBufferMountItemUpdateLayout(int reactTag, View view, int parentTag, View parentView, + int x, int y, int width, int height, int displayType) { + super(InstructionType.UPDATE_LAYOUT, reactTag, view); + this.parentTag = parentTag; + this.parentView = parentView; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.displayType = displayType; + } + + public int getParentTag() { + return parentTag; + } + + public View getParentView() { + return parentView; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getDisplayType() { + return displayType; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateOverflowInset.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateOverflowInset.java new file mode 100644 index 000000000000..aeef222b8b1a --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateOverflowInset.java @@ -0,0 +1,39 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; + +import android.view.View; + +public class IntBufferMountItemUpdateOverflowInset extends IntBufferMountItem { + + private int overflowInsetLeft; + private int overflowInsetTop; + private int overflowInsetRight; + private int overflowInsetBottom; + + public IntBufferMountItemUpdateOverflowInset(int reactTag, View view, int overflowInsetLeft, int overflowInsetTop, int overflowInsetRight, + int overflowInsetBottom) { + super(InstructionType.UPDATE_OVERFLOW_INSET, reactTag, view); + this.overflowInsetLeft = overflowInsetLeft; + this.overflowInsetTop = overflowInsetTop; + this.overflowInsetRight = overflowInsetRight; + this.overflowInsetBottom = overflowInsetBottom; + } + + public int getOverflowInsetLeft() { + return overflowInsetLeft; + } + + public int getOverflowInsetTop() { + return overflowInsetTop; + } + + public int getOverflowInsetRight() { + return overflowInsetRight; + } + + public int getOverflowInsetBottom() { + return overflowInsetBottom; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdatePadding.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdatePadding.java new file mode 100644 index 000000000000..f405526f74fb --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdatePadding.java @@ -0,0 +1,40 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; + +import android.view.View; + +public class IntBufferMountItemUpdatePadding extends IntBufferMountItem { + + + private int left; + private int top; + private int right; + private int bottom; + + public IntBufferMountItemUpdatePadding(int reactTag, View view, int left, int top, int right, + int bottom) { + super(InstructionType.UPDATE_PADDING, reactTag, view); + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + public int getLeft() { + return left; + } + + public int getTop() { + return top; + } + + public int getRight() { + return right; + } + + public int getBottom() { + return bottom; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateProps.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateProps.java new file mode 100644 index 000000000000..a06a66b63d47 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateProps.java @@ -0,0 +1,20 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; + +import android.view.View; + +public class IntBufferMountItemUpdateProps extends IntBufferMountItem { + + private final Object props; + + public IntBufferMountItemUpdateProps(int reactTag, View view, Object props) { + super(InstructionType.UPDATE_PROPS, reactTag, view); + this.props = props; + } + + public Object getProps() { + return props; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateState.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateState.java new file mode 100644 index 000000000000..0006e58522b8 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferMountItemUpdateState.java @@ -0,0 +1,22 @@ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; +import com.facebook.react.fabric.mounting.mountitems.InstructionType; +import com.facebook.react.uimanager.StateWrapper; + +import android.view.View; + + +public class IntBufferMountItemUpdateState extends IntBufferMountItem { + + private final StateWrapper stateWrapper; + + public IntBufferMountItemUpdateState(int reactTag, View view, StateWrapper stateWrapper) { + super(InstructionType.UPDATE_STATE, reactTag, view); + this.stateWrapper = stateWrapper; + } + + public StateWrapper getStateWrapper() { + return stateWrapper; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 18457d278ffd..331ede5e904c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -46,6 +46,7 @@ import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.uimanager.events.EventDispatcherImpl; import com.facebook.react.uimanager.events.RCTEventEmitter; +import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; import java.util.ArrayList; @@ -804,7 +805,7 @@ public void removeViewMutationsListener(ViewMutationsListener listener) { mViewMutationsListeners.remove(listener); } - public void viewMutationsWillMount(ArrayList> mutations) { + public void viewMutationsWillMount(ArrayList mutations) { for (ViewMutationsListener listener : mViewMutationsListeners) { listener.willMountViewMutations(mutations); } From b595ec18e0431cafb662ba92dec4438f8f9ba219 Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Tue, 10 Oct 2023 16:09:16 +0200 Subject: [PATCH 6/7] fix: comment --- .../fabric/mounting/mountitems/IntBufferBatchMountItem.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java index 4d10fad5ca72..e9309505ce19 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java @@ -124,8 +124,8 @@ public void execute(@NonNull MountingManager mountingManager) { ArrayList mutationsArray = new ArrayList<>(); - // we put views in the map also for basic operations since tags are only mapped to ViewState - // which are internal. + // we put views in the mount item objects also for some operations since tags + // are only mapped to ViewState which are internal. // In most cases we will need the view to perform an action in the listener int i = 0, j = 0; while (i < mIntBufferLen) { From 887683aa3ae12d2d58599287a6a8d0363ff8c2ed Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Tue, 17 Oct 2023 16:37:39 +0200 Subject: [PATCH 7/7] fix: restore missing import for View --- .../fabric/mounting/mountitems/IntBufferBatchMountItem.java | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java index e9309505ce19..e6b073958678 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import android.view.View; /** * This class represents a batch of {@link MountItem}s, represented directly as int buffers to