mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
d9deee20e7
Summary: ## Context `NativeModuleRegistryBuilder` calls `TurboReactPackage.getNativeModuleIterator()` to access ModuleHolders for all the NativeModules in the `TurboReactPackage`. We then filter out the ModuleHolders that contain `TurboModules`, before using that list to make create the `NativeModuleRegistry`. ## Problem Creating `ModuleHolders` has the side-effect of actually creating the NativeModule if it requires eager initialization. See [ModuleHolder.java](https://fburl.com/diffusion/4avdtio0): ``` class ModuleHolder { // ... public ModuleHolder(ReactModuleInfo moduleInfo, Provider<? extends NativeModule> provider) { mName = moduleInfo.name(); mProvider = provider; mReactModuleInfo = moduleInfo; if (moduleInfo.needsEagerInit()) { mModule = create(); // HERE! } } ``` So, we need to filter out TurboModules before we even create ModuleHolders. Changelog: [Android][Fixed] - Refactor TurboModule filtering in NativeModuleRegistryBuilder Reviewed By: PeteTheHeat, mdvacca Differential Revision: D18814010 fbshipit-source-id: a120d2b619b9280ba70e21d131dccc5a9fc6346d
163 lines
5.6 KiB
Java
163 lines
5.6 KiB
Java
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
package com.facebook.react;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import com.facebook.react.bridge.ModuleHolder;
|
|
import com.facebook.react.bridge.ModuleSpec;
|
|
import com.facebook.react.bridge.NativeModule;
|
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
import com.facebook.react.config.ReactFeatureFlags;
|
|
import com.facebook.react.module.model.ReactModuleInfo;
|
|
import com.facebook.react.module.model.ReactModuleInfoProvider;
|
|
import com.facebook.react.uimanager.ViewManager;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.Set;
|
|
import javax.inject.Provider;
|
|
|
|
/** This will eventually replace {@link LazyReactPackage} when TurboModules are finally done. */
|
|
public abstract class TurboReactPackage implements ReactPackage {
|
|
|
|
@Override
|
|
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
|
throw new UnsupportedOperationException(
|
|
"In case of TurboModules, createNativeModules is not supported. NativeModuleRegistry should instead use getModuleList or getModule method");
|
|
}
|
|
|
|
/**
|
|
* The API needed for TurboModules. Given a module name, it returns an instance of {@link
|
|
* NativeModule} for the name
|
|
*
|
|
* @param name
|
|
* @param reactContext
|
|
* @return
|
|
*/
|
|
public abstract NativeModule getModule(String name, final ReactApplicationContext reactContext);
|
|
|
|
/**
|
|
* This is a temporary method till we implement TurboModules. Once we implement TurboModules, we
|
|
* will be able to directly call {@link TurboReactPackage#getModule(String,
|
|
* ReactApplicationContext)} This method will be removed when TurboModule implementation is
|
|
* complete
|
|
*
|
|
* @param reactContext
|
|
* @return
|
|
*/
|
|
public Iterable<ModuleHolder> getNativeModuleIterator(
|
|
final ReactApplicationContext reactContext) {
|
|
final Set<Map.Entry<String, ReactModuleInfo>> entrySet =
|
|
getReactModuleInfoProvider().getReactModuleInfos().entrySet();
|
|
final Iterator<Map.Entry<String, ReactModuleInfo>> entrySetIterator = entrySet.iterator();
|
|
return new Iterable<ModuleHolder>() {
|
|
@NonNull
|
|
@Override
|
|
// This should ideally be an IteratorConvertor, but we don't have any internal library for it
|
|
public Iterator<ModuleHolder> iterator() {
|
|
return new Iterator<ModuleHolder>() {
|
|
Map.Entry<String, ReactModuleInfo> nextEntry = null;
|
|
|
|
private void findNext() {
|
|
while (entrySetIterator.hasNext()) {
|
|
Map.Entry<String, ReactModuleInfo> entry = entrySetIterator.next();
|
|
ReactModuleInfo reactModuleInfo = entry.getValue();
|
|
|
|
// This Iterator is used to create the NativeModule registry. The NativeModule
|
|
// registry must not have TurboModules. Therefore, if TurboModules are enabled, and
|
|
// the current NativeModule is a TurboModule, we need to skip iterating over it.
|
|
if (ReactFeatureFlags.useTurboModules && reactModuleInfo.isTurboModule()) {
|
|
continue;
|
|
}
|
|
|
|
nextEntry = entry;
|
|
return;
|
|
}
|
|
nextEntry = null;
|
|
}
|
|
|
|
@Override
|
|
public boolean hasNext() {
|
|
if (nextEntry == null) {
|
|
findNext();
|
|
}
|
|
return nextEntry != null;
|
|
}
|
|
|
|
@Override
|
|
public ModuleHolder next() {
|
|
if (nextEntry == null) {
|
|
findNext();
|
|
}
|
|
|
|
if (nextEntry == null) {
|
|
throw new NoSuchElementException("ModuleHolder not found");
|
|
}
|
|
|
|
Map.Entry<String, ReactModuleInfo> entry = nextEntry;
|
|
|
|
// Advance iterator
|
|
findNext();
|
|
String name = entry.getKey();
|
|
ReactModuleInfo reactModuleInfo = entry.getValue();
|
|
return new ModuleHolder(reactModuleInfo, new ModuleHolderProvider(name, reactContext));
|
|
}
|
|
|
|
@Override
|
|
public void remove() {
|
|
throw new UnsupportedOperationException("Cannot remove native modules from the list");
|
|
}
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @param reactContext react application context that can be used to create View Managers.
|
|
* @return list of module specs that can create the View Managers.
|
|
*/
|
|
protected List<ModuleSpec> getViewManagers(ReactApplicationContext reactContext) {
|
|
return Collections.emptyList();
|
|
}
|
|
|
|
@Override
|
|
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
|
List<ModuleSpec> viewManagerModuleSpecs = getViewManagers(reactContext);
|
|
if (viewManagerModuleSpecs == null || viewManagerModuleSpecs.isEmpty()) {
|
|
return Collections.emptyList();
|
|
}
|
|
|
|
List<ViewManager> viewManagers = new ArrayList<>();
|
|
for (ModuleSpec moduleSpec : viewManagerModuleSpecs) {
|
|
viewManagers.add((ViewManager) moduleSpec.getProvider().get());
|
|
}
|
|
return viewManagers;
|
|
}
|
|
|
|
public abstract ReactModuleInfoProvider getReactModuleInfoProvider();
|
|
|
|
private class ModuleHolderProvider implements Provider<NativeModule> {
|
|
|
|
private final String mName;
|
|
private final ReactApplicationContext mReactContext;
|
|
|
|
public ModuleHolderProvider(String name, ReactApplicationContext reactContext) {
|
|
mName = name;
|
|
mReactContext = reactContext;
|
|
}
|
|
|
|
@Override
|
|
public NativeModule get() {
|
|
return getModule(mName, mReactContext);
|
|
}
|
|
}
|
|
}
|