Repository navigation
Return only view manager names from bridgeless UIManager.getConstants() - #59173
brownrice777 wants to merge 1 commit into
Conversation
In bridgeless mode, UIManager.getConstants() builds the constants of all eager view managers. This step uses reflection on each view manager. BridgelessUIManager calls getConstants() when it loads. Thus, each cold start does this work before the first screen. This change makes getConstants() return the same data as the old architecture with lazy view managers: the UIManager constants and the names of all view managers. When JS needs the constants of one view manager, it calls getConstantsForViewManager(). This function finds eager and lazy view managers. The JS code does not change. BridgelessUIManager makes a lazy getter for each name. getViewManagerConfig() uses getConstantsForViewManager(). getNativeComponentAttributes() uses getDefaultEventTypes().
|
Hi @brownrice777! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
|
Have you checked the threading model here? It's generally unsafe to access UI constants from the JS thread, which is why we usually end up pre-loading them here. |
Summary:
In bridgeless mode on Android,
UIManager.getConstants()builds the constants of all eager view managers. This step uses reflection on the@ReactPropsetters of each view manager.BridgelessUIManagercallsgetConstants()when the module loads. Thus, each cold start does this work on the JS thread, before the first screen.Many apps cannot make their view managers lazy, because libraries register them. In the app that I measured, 130 view managers are eager: 98 from
expo-modules-core, 19 fromreact-native-screensand 13 from other libraries. 47 view managers are lazy.This change makes
getConstants()return the same data as the old architecture with lazy view managers (UIManagerModuleConstantsHelper.createConstants(ViewManagerResolver)): the UIManager constants, the names of all view managers, andLazyViewManagersEnabled. When JS needs the constants of one view manager, it callsgetConstantsForViewManager(). This function finds eager and lazy view managers.The JS code does not change:
BridgelessUIManagermakes a lazy getter for each name. Thus,UIManager.SomeViewManagercontinues to work (see Preserve lazy ViewManager initialization in UIManager #58097).getViewManagerConfig()gets the constants of a view manager fromgetConstantsForViewManager()on first use.getNativeComponentAttributes()uses theLazyViewManagersEnabledpath, which callsgetDefaultEventTypes().One result is visible:
UIManager.getConstants()does not contain the constants of eager view managers,genericBubblingEventTypesorgenericDirectEventTypes. This is the same as the old architecture with lazy view managers.Changelog:
[ANDROID] [CHANGED] - In bridgeless mode,
UIManager.getConstants()returns only the view manager names. JS gets the constants of a view manager when it needs them.Test Plan:
Device: Xiaomi Mi Note 2 (Snapdragon 821, Android 8.0). App: a production Expo app, release build, React Native 0.86, Hermes. Each build was installed new. I did each cold start with
am force-stop, thenam start -W. The measured point is the first frame with rows in the first list.I did not build React Native from source. To measure the effect, I replaced the
RN$LegacyInterop_UIManager_getConstantsbinding in JS with a function that returns the result of this change: the names of the 177 view managers of the app and the UIManager constants. I got these values from the real binding on the same device.getConstants()timeThe ranges do not overlap: 2762–2879 ms before, 2365–2467 ms after.
I also did these checks on the device with the simulated binding:
getConstants()occurs one time for each start, and it returns only names.The Kotlin change uses
UIManagerModuleConstantsHelper.createConstants(ViewManagerResolver), whichUIManagerModuleuses for the old architecture.BridgelessViewManagerResolveris aViewManagerResolver. CI compiles the change.