diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index a6027ba3c..6075cda13 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -1,10 +1,9 @@ /** * 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. + *

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.uimanager; import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_CONSTANTS_END; @@ -15,6 +14,7 @@ import android.content.ComponentCallbacks2; import android.content.Context; import android.content.res.Configuration; import android.media.AudioManager; +import android.util.ArrayMap; import com.facebook.common.logging.FLog; import com.facebook.debug.holder.PrinterHolder; import com.facebook.debug.tags.ReactDebugOverlayTags; @@ -44,52 +44,52 @@ import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import javax.annotation.Nullable; /** - *

Native module to allow JS to create and update native Views.

+ * Native module to allow JS to create and update native Views. * *

+ * *

== Transactional Requirement ==

+ * * A requirement of this class is to make sure that transactional UI updates occur all at once, * meaning that no intermediate state is ever rendered to the screen. For example, if a JS * application update changes the background of View A to blue and the width of View B to 100, both * need to appear at once. Practically, this means that all UI update code related to a single * transaction must be executed as a single code block on the UI thread. Executing as multiple code * blocks could allow the platform UI system to interrupt and render a partial UI state. - *

* *

To facilitate this, this module enqueues operations that are then applied to native view * hierarchy through {@link NativeViewHierarchyManager} at the end of each transaction. * *

- *

== CSSNodes ==

- * In order to allow layout and measurement to occur on a non-UI thread, this module also - * operates on intermediate CSSNodeDEPRECATED objects that correspond to a native view. These CSSNodeDEPRECATED are able - * to calculate layout according to their styling rules, and then the resulting x/y/width/height of - * that layout is scheduled as an operation that will be applied to native view hierarchy at the end - * of current batch. - *

* - * TODO(5241856): Investigate memory usage of creating many small objects in UIManageModule and - * consider implementing a pool - * TODO(5483063): Don't dispatch the view hierarchy at the end of a batch if no UI changes occurred + *

== CSSNodes ==

+ * + * In order to allow layout and measurement to occur on a non-UI thread, this module also operates + * on intermediate CSSNodeDEPRECATED objects that correspond to a native view. These + * CSSNodeDEPRECATED are able to calculate layout according to their styling rules, and then the + * resulting x/y/width/height of that layout is scheduled as an operation that will be applied to + * native view hierarchy at the end of current batch. TODO(5241856): Investigate memory usage of + * creating many small objects in UIManageModule and consider implementing a pool TODO(5483063): + * Don't dispatch the view hierarchy at the end of a batch if no UI changes occurred */ @ReactModule(name = UIManagerModule.NAME) -public class UIManagerModule extends ReactContextBaseJavaModule implements - OnBatchCompleteListener, LifecycleEventListener, UIManager { +public class UIManagerModule extends ReactContextBaseJavaModule + implements OnBatchCompleteListener, LifecycleEventListener, UIManager { - /** - * Enables lazy discovery of a specific {@link ViewManager} by its name. - */ + /** Enables lazy discovery of a specific {@link ViewManager} by its name. */ public interface ViewManagerResolver { /** - * {@class UIManagerModule} class uses this method to get a ViewManager by its name. - * This is the same name that comes from JS by {@code UIManager.ViewManagerName} call. + * {@class UIManagerModule} class uses this method to get a ViewManager by its name. This is the + * same name that comes from JS by {@code UIManager.ViewManagerName} call. */ - @Nullable ViewManager getViewManager(String viewManagerName); + @Nullable + ViewManager getViewManager(String viewManagerName); /** * Provides a list of view manager names to register in JS as {@code UIManager.ViewManagerName} @@ -97,14 +97,11 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements List getViewManagerNames(); } - /** - * Resolves a name coming from native side to a name of the event that is exposed to JS. - */ + /** Resolves a name coming from native side to a name of the event that is exposed to JS. */ public interface CustomEventNamesResolver { - /** - * Returns custom event name by the provided event name. - */ - @Nullable String resolveCustomEventName(String eventName); + /** Returns custom event name by the provided event name. */ + @Nullable + String resolveCustomEventName(String eventName); } public static final String NAME = "UIManager"; @@ -118,6 +115,8 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements private final UIImplementation mUIImplementation; private final MemoryTrimCallback mMemoryTrimCallback = new MemoryTrimCallback(); private final List mListeners = new ArrayList<>(); + private @Nullable Map mViewManagerConstantsCache; + volatile private int mViewManagerConstantsCacheSize; private int mBatchId = 0; @@ -180,8 +179,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements public void initialize() { getReactApplicationContext().registerComponentCallbacks(mMemoryTrimCallback); mEventDispatcher.registerEventEmitter( - DEFAULT, - getReactApplicationContext().getJSModule(RCTEventEmitter.class)); + DEFAULT, getReactApplicationContext().getJSModule(RCTEventEmitter.class)); } @Override @@ -212,10 +210,9 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements private static Map createConstants(ViewManagerResolver viewManagerResolver) { ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_CONSTANTS_START); - SystraceMessage.beginSection( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants") - .arg("Lazy", true) - .flush(); + SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants") + .arg("Lazy", true) + .flush(); try { return UIManagerModuleConstantsHelper.createConstants(viewManagerResolver); } finally { @@ -229,10 +226,9 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements @Nullable Map customBubblingEvents, @Nullable Map customDirectEvents) { ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_CONSTANTS_START); - SystraceMessage.beginSection( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants") - .arg("Lazy", false) - .flush(); + SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants") + .arg("Lazy", false) + .flush(); try { return UIManagerModuleConstantsHelper.createConstants( viewManagers, customBubblingEvents, customDirectEvents); @@ -242,8 +238,48 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements } } + /** + * Helper method to pre-compute the constants for a view manager. This method ensures that we + * don't block for getting the constants for view managers during TTI + * + * @param viewManagerNames + */ + @Deprecated + public void preComputeConstantsForViewManager(List viewManagerNames) { + Map constantsMap = new ArrayMap<>(); + for (String viewManagerName : viewManagerNames) { + WritableMap constants = computeConstantsForViewManager(viewManagerName); + if (constants != null) { + constantsMap.put(viewManagerName, constants); + } + } + + // To ensure that this is thread safe, we return an unmodifiableMap + // We use mViewManagerConstantsCacheSize to count the times we access the contents of the map + // Once we have accessed all the values, we free this cache + // Assumption is that JS gets the constants only once for each viewManager. + // Using this mechanism prevents expensive synchronized blocks, due to the nature of how this is + // accessed - write one, read multiple times, and then throw the data away. + mViewManagerConstantsCacheSize = viewManagerNames.size(); + mViewManagerConstantsCache = Collections.unmodifiableMap(constantsMap); + } + @ReactMethod(isBlockingSynchronousMethod = true) public @Nullable WritableMap getConstantsForViewManager(final String viewManagerName) { + if (mViewManagerConstantsCache != null + && mViewManagerConstantsCache.containsKey(viewManagerName)) { + WritableMap constants = mViewManagerConstantsCache.get(viewManagerName); + if (--mViewManagerConstantsCacheSize <= 0) { + // Looks like we have read all the values from the cache, so we may as well free this cache + mViewManagerConstantsCache = null; + } + return constants; + } else { + return computeConstantsForViewManager(viewManagerName); + } + } + + private @Nullable WritableMap computeConstantsForViewManager(final String viewManagerName) { ViewManager targetView = viewManagerName != null ? mUIImplementation.resolveViewManager(viewManagerName) : null; if (targetView == null) { @@ -310,29 +346,27 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements @Override public int addRootView( final T rootView) { - Systrace.beginSection( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, - "UIManagerModule.addRootView"); + Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "UIManagerModule.addRootView"); final int tag = ReactRootViewTagGenerator.getNextRootViewTag(); final ReactApplicationContext reactApplicationContext = getReactApplicationContext(); final ThemedReactContext themedRootContext = - new ThemedReactContext(reactApplicationContext, rootView.getContext()); + new ThemedReactContext(reactApplicationContext, rootView.getContext()); mUIImplementation.registerRootView(rootView, tag, themedRootContext); rootView.setOnSizeChangedListener( - new SizeMonitoringFrameLayout.OnSizeChangedListener() { - @Override - public void onSizeChanged(final int width, final int height, int oldW, int oldH) { - reactApplicationContext.runOnNativeModulesQueueThread( - new GuardedRunnable(reactApplicationContext) { - @Override - public void runGuarded() { - updateNodeSize(tag, width, height); - } - }); - } - }); + new SizeMonitoringFrameLayout.OnSizeChangedListener() { + @Override + public void onSizeChanged(final int width, final int height, int oldW, int oldH) { + reactApplicationContext.runOnNativeModulesQueueThread( + new GuardedRunnable(reactApplicationContext) { + @Override + public void runGuarded() { + updateNodeSize(tag, width, height); + } + }); + } + }); Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); return tag; @@ -350,13 +384,11 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements } /** - * Sets local data for a shadow node corresponded with given tag. - * In some cases we need a way to specify some environmental data to shadow node - * to improve layout (or do something similar), so {@code localData} serves these needs. - * For example, any stateful embedded native views may benefit from this. - * Have in mind that this data is not supposed to interfere with the state of - * the shadow view. - * Please respect one-directional data flow of React. + * Sets local data for a shadow node corresponded with given tag. In some cases we need a way to + * specify some environmental data to shadow node to improve layout (or do something similar), so + * {@code localData} serves these needs. For example, any stateful embedded native views may + * benefit from this. Have in mind that this data is not supposed to interfere with the state of + * the shadow view. Please respect one-directional data flow of React. */ public void setViewLocalData(final int tag, final Object data) { final ReactApplicationContext reactApplicationContext = getReactApplicationContext(); @@ -403,7 +435,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements * @param addChildTags a list of tags of views to add to the parent * @param addAtIndices parallel to addChildTags, a list of indices to insert those children at * @param removeFrom a list of indices of views to permanently remove. The memory for the - * corresponding views and data structures should be reclaimed. + * corresponding views and data structures should be reclaimed. */ @ReactMethod public void manageChildren( @@ -431,25 +463,18 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements PrinterHolder.getPrinter().logMessage(ReactDebugOverlayTags.UI_MANAGER, message); } mUIImplementation.manageChildren( - viewTag, - moveFrom, - moveTo, - addChildTags, - addAtIndices, - removeFrom); + viewTag, moveFrom, moveTo, addChildTags, addAtIndices, removeFrom); } /** - * Interface for fast tracking the initial adding of views. Children view tags are assumed to be + * Interface for fast tracking the initial adding of views. Children view tags are assumed to be * in order * * @param viewTag the view tag of the parent view * @param childrenTags An array of tags to add to the parent in order */ @ReactMethod - public void setChildren( - int viewTag, - ReadableArray childrenTags) { + public void setChildren(int viewTag, ReadableArray childrenTags) { if (DEBUG) { String message = "(UIManager.setChildren) tag: " + viewTag + ", children: " + childrenTags; FLog.d(ReactConstants.TAG, message); @@ -470,8 +495,8 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements /** * Method which takes a container tag and then releases all subviews for that container upon - * receipt. - * TODO: The method name is incorrect and will be renamed, #6033872 + * receipt. TODO: The method name is incorrect and will be renamed, #6033872 + * * @param containerTag the tag of the container for which the subviews must be removed */ @ReactMethod @@ -490,7 +515,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements /** * Determines the location on screen, width, and height of the given view relative to the device - * screen and returns the values via an async callback. This is the absolute position including + * screen and returns the values via an async callback. This is the absolute position including * things like the status bar */ @ReactMethod @@ -501,74 +526,61 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements /** * Measures the view specified by tag relative to the given ancestorTag. This means that the * returned x, y are relative to the origin x, y of the ancestor view. Results are stored in the - * given outputBuffer. We allow ancestor view and measured view to be the same, in which case - * the position always will be (0, 0) and method will only measure the view dimensions. + * given outputBuffer. We allow ancestor view and measured view to be the same, in which case the + * position always will be (0, 0) and method will only measure the view dimensions. * - * NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible + *

NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible * window which can cause unexpected results when measuring relative to things like ScrollViews * that can have offset content on the screen. */ @ReactMethod public void measureLayout( - int tag, - int ancestorTag, - Callback errorCallback, - Callback successCallback) { + int tag, int ancestorTag, Callback errorCallback, Callback successCallback) { mUIImplementation.measureLayout(tag, ancestorTag, errorCallback, successCallback); } /** * Like {@link #measure} and {@link #measureLayout} but measures relative to the immediate parent. * - * NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible + *

NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible * window which can cause unexpected results when measuring relative to things like ScrollViews * that can have offset content on the screen. */ @ReactMethod public void measureLayoutRelativeToParent( - int tag, - Callback errorCallback, - Callback successCallback) { + int tag, Callback errorCallback, Callback successCallback) { mUIImplementation.measureLayoutRelativeToParent(tag, errorCallback, successCallback); } /** - * Find the touch target child native view in the supplied root view hierarchy, given a react + * Find the touch target child native view in the supplied root view hierarchy, given a react * target location. * - * This method is currently used only by Element Inspector DevTool. + *

This method is currently used only by Element Inspector DevTool. * * @param reactTag the tag of the root view to traverse * @param point an array containing both X and Y target location * @param callback will be called if with the identified child view react ID, and measurement - * info. If no view was found, callback will be invoked with no data. + * info. If no view was found, callback will be invoked with no data. */ @ReactMethod public void findSubviewIn( - final int reactTag, - final ReadableArray point, - final Callback callback) { + final int reactTag, final ReadableArray point, final Callback callback) { mUIImplementation.findSubviewIn( - reactTag, - Math.round(PixelUtil.toPixelFromDIP(point.getDouble(0))), - Math.round(PixelUtil.toPixelFromDIP(point.getDouble(1))), - callback); + reactTag, + Math.round(PixelUtil.toPixelFromDIP(point.getDouble(0))), + Math.round(PixelUtil.toPixelFromDIP(point.getDouble(1))), + callback); } - /** - * Check if the first shadow node is the descendant of the second shadow node - */ + /** Check if the first shadow node is the descendant of the second shadow node */ @ReactMethod public void viewIsDescendantOf( - final int reactTag, - final int ancestorReactTag, - final Callback callback) { + final int reactTag, final int ancestorReactTag, final Callback callback) { mUIImplementation.viewIsDescendantOf(reactTag, ancestorReactTag, callback); } - /** - * Registers a new Animation that can then be added to a View using {@link #addAnimation}. - */ + /** Registers a new Animation that can then be added to a View using {@link #addAnimation}. */ public void registerAnimation(Animation animation) { mUIImplementation.registerAnimation(animation); } @@ -580,9 +592,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements mUIImplementation.addAnimation(reactTag, animationID, onSuccess); } - /** - * Removes an existing Animation, canceling it if it was in progress. - */ + /** Removes an existing Animation, canceling it if it was in progress. */ public void removeAnimation(int reactTag, int animationID) { mUIImplementation.removeAnimation(reactTag, animationID); } @@ -600,11 +610,12 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void dispatchViewManagerCommand(int reactTag, int commandId, @Nullable ReadableArray commandArgs) { - //TODO: this is a temporary approach to support ViewManagerCommands in Fabric until + public void dispatchViewManagerCommand( + int reactTag, int commandId, @Nullable ReadableArray commandArgs) { + // TODO: this is a temporary approach to support ViewManagerCommands in Fabric until // the dispatchViewManagerCommand() method is supported by Fabric JS API. UIManagerHelper.getUIManager(getReactApplicationContext(), ViewUtil.getUIManagerType(reactTag)) - .dispatchCommand(reactTag, commandId, commandArgs); + .dispatchCommand(reactTag, commandId, commandArgs); } @Override @@ -614,7 +625,8 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements @ReactMethod public void playTouchSound() { - AudioManager audioManager = (AudioManager) getReactApplicationContext().getSystemService(Context.AUDIO_SERVICE); + AudioManager audioManager = + (AudioManager) getReactApplicationContext().getSystemService(Context.AUDIO_SERVICE); if (audioManager != null) { audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); } @@ -624,11 +636,11 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements * Show a PopupMenu. * * @param reactTag the tag of the anchor view (the PopupMenu is displayed next to this view); this - * needs to be the tag of a native view (shadow views can not be anchors) + * needs to be the tag of a native view (shadow views can not be anchors) * @param items the menu items as an array of strings * @param error will be called if there is an error displaying the menu * @param success will be called with the position of the selected item as the first argument, or - * no arguments if the menu is dismissed + * no arguments if the menu is dismissed */ @ReactMethod public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Callback success) { @@ -644,10 +656,10 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements * LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled * explicitly in order to avoid regression in existing application written for iOS using this API. * - * Warning : This method will be removed in future version of React Native, and layout animation - * will be enabled by default, so always check for its existence before invoking it. + *

Warning : This method will be removed in future version of React Native, and layout + * animation will be enabled by default, so always check for its existence before invoking it. * - * TODO(9139831) : remove this method once layout animation is fully stable. + *

TODO(9139831) : remove this method once layout animation is fully stable. * * @param enabled whether layout animation is enabled or not */ @@ -657,38 +669,35 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements } /** - * Configure an animation to be used for the native layout changes, and native views - * creation. The animation will only apply during the current batch operations. + * Configure an animation to be used for the native layout changes, and native views creation. The + * animation will only apply during the current batch operations. * - * TODO(7728153) : animating view deletion is currently not supported. - * TODO(7613721) : callbacks are not supported, this feature will likely be killed. + *

TODO(7728153) : animating view deletion is currently not supported. TODO(7613721) : + * callbacks are not supported, this feature will likely be killed. * * @param config the configuration of the animation for view addition/removal/update. * @param success will be called when the animation completes, or when the animation get - * interrupted. In this case, callback parameter will be false. + * interrupted. In this case, callback parameter will be false. * @param error will be called if there was an error processing the animation */ @ReactMethod - public void configureNextLayoutAnimation( - ReadableMap config, - Callback success, - Callback error) { + public void configureNextLayoutAnimation(ReadableMap config, Callback success, Callback error) { mUIImplementation.configureNextLayoutAnimation(config, success, error); } /** - * To implement the transactional requirement mentioned in the class javadoc, we only commit - * UI changes to the actual view hierarchy once a batch of JS->Java calls have been completed. - * We know this is safe because all JS->Java calls that are triggered by a Java->JS call (e.g. - * the delivery of a touch event or execution of 'renderApplication') end up in a single - * JS->Java transaction. + * To implement the transactional requirement mentioned in the class javadoc, we only commit UI + * changes to the actual view hierarchy once a batch of JS->Java calls have been completed. We + * know this is safe because all JS->Java calls that are triggered by a Java->JS call (e.g. the + * delivery of a touch event or execution of 'renderApplication') end up in a single JS->Java + * transaction. * - * A better way to do this would be to have JS explicitly signal to this module when a UI - * transaction is done. Right now, though, this is how iOS does it, and we should probably - * update the JS and native code and make this change at the same time. + *

A better way to do this would be to have JS explicitly signal to this module when a UI + * transaction is done. Right now, though, this is how iOS does it, and we should probably update + * the JS and native code and make this change at the same time. * - * TODO(5279396): Make JS UI library explicitly notify the native UI module of the end of a UI - * transaction using a standard native call + *

TODO(5279396): Make JS UI library explicitly notify the native UI module of the end of a UI + * transaction using a standard native call */ @Override public void onBatchComplete() { @@ -696,8 +705,8 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements mBatchId++; SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onBatchCompleteUI") - .arg("BatchId", batchId) - .flush(); + .arg("BatchId", batchId) + .flush(); for (UIManagerModuleListener listener : mListeners) { listener.willDispatchViewUpdates(this); } @@ -723,28 +732,23 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements } /** - * Schedule a block to be executed on the UI thread. Useful if you need to execute - * view logic after all currently queued view updates have completed. + * Schedule a block to be executed on the UI thread. Useful if you need to execute view logic + * after all currently queued view updates have completed. * * @param block that contains UI logic you want to execute. - * - * Usage Example: - - UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class); - uiManager.addUIBlock(new UIBlock() { - public void execute (NativeViewHierarchyManager nvhm) { - View view = nvhm.resolveView(tag); - // ...execute your code on View (e.g. snapshot the view) - } - }); - */ + *

Usage Example: + *

UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class); + * uiManager.addUIBlock(new UIBlock() { public void execute (NativeViewHierarchyManager nvhm) + * { View view = nvhm.resolveView(tag); // ...execute your code on View (e.g. snapshot the + * view) } }); + */ public void addUIBlock(UIBlock block) { mUIImplementation.addUIBlock(block); } /** - * Schedule a block to be executed on the UI thread. Useful if you need to execute - * view logic before all currently queued view updates have completed. + * Schedule a block to be executed on the UI thread. Useful if you need to execute view logic + * before all currently queued view updates have completed. * * @param block that contains UI logic you want to execute. */ @@ -761,12 +765,10 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements } /** - * 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. + * 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. * * @param reactTag the component tag - * * @return the rootTag */ public int resolveRootTagFromReactTag(int reactTag) { @@ -790,15 +792,17 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements * Updates the styles of the {@link ReactShadowNode} based on the Measure specs received by * parameters. */ - public void updateRootLayoutSpecs(final int rootViewTag, final int widthMeasureSpec, final int heightMeasureSpec) { + public void updateRootLayoutSpecs( + final int rootViewTag, final int widthMeasureSpec, final int heightMeasureSpec) { ReactApplicationContext reactApplicationContext = getReactApplicationContext(); reactApplicationContext.runOnNativeModulesQueueThread( - new GuardedRunnable(reactApplicationContext) { - @Override - public void runGuarded() { - mUIImplementation.updateRootView(rootViewTag, widthMeasureSpec, heightMeasureSpec); - mUIImplementation.dispatchViewUpdates(-1); - }}); + new GuardedRunnable(reactApplicationContext) { + @Override + public void runGuarded() { + mUIImplementation.updateRootView(rootViewTag, widthMeasureSpec, heightMeasureSpec); + mUIImplementation.dispatchViewUpdates(-1); + } + }); } /** Listener that drops the CSSNode pool on low memory when the app is backgrounded. */ @@ -812,11 +816,9 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements } @Override - public void onConfigurationChanged(Configuration newConfig) { - } + public void onConfigurationChanged(Configuration newConfig) {} @Override - public void onLowMemory() { - } + public void onLowMemory() {} } }