Pass State to preallocateView and createView methods whenever possible

Summary:
For some components, we will have state as soon as the ShadowNode is created that may be meaningful. In those cases, ViewManagers should be able to use State to create or preallocate views.

FB: This will be used in following diffs for Litho support.

Reviewed By: mdvacca

Differential Revision: D15343702

fbshipit-source-id: 8fd672251cb88dea662b5cae5a9efc96877d28a9
This commit is contained in:
Joshua Gross
2019-05-21 15:05:18 -07:00
committed by Facebook Github Bot
parent c9df1db00a
commit b05761f1bb
12 changed files with 67 additions and 41 deletions
@@ -176,6 +176,7 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
int reactTag,
final String componentName,
@Nullable ReadableMap props,
Object stateWrapper,
boolean isLayoutable) {
ThemedReactContext context = mReactContextForRootTag.get(rootTag);
String component = getFabricComponentName(componentName);
@@ -187,6 +188,7 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
reactTag,
component,
props,
(StateWrapper) stateWrapper,
isLayoutable));
}
}
@@ -290,14 +290,17 @@ local_ref<JMountItem::javaobject> createUpdateStateMountItem(
// Do not hold onto Java object from C
// We DO want to hold onto C object from Java, since we don't know the
// lifetime of the Java object
auto javaStateWrapper = StateWrapperImpl::newObjectJavaArgs();
StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper);
cStateWrapper->state_ = state;
local_ref<StateWrapperImpl::JavaPart> javaStateWrapper = nullptr;
if (state != nullptr) {
javaStateWrapper = StateWrapperImpl::newObjectJavaArgs();
StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper);
cStateWrapper->state_ = state;
}
return updateStateInstruction(
javaUIManager,
mutation.newChildShadowView.tag,
javaStateWrapper.get());
(javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr));
}
@@ -525,13 +528,23 @@ void Binding::schedulerDidRequestPreliminaryViewAllocation(
static auto preallocateView =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void(jint, jint, jstring, ReadableMap::javaobject, jboolean)>("preallocateView");
->getMethod<void(jint, jint, jstring, ReadableMap::javaobject, jobject, jboolean)>("preallocateView");
local_ref<ReadableMap::javaobject> readableMap =
// Do not hold onto Java object from C
// We DO want to hold onto C object from Java, since we don't know the
// lifetime of the Java object
local_ref<StateWrapperImpl::JavaPart> javaStateWrapper = nullptr;
if (shadowView.state != nullptr) {
javaStateWrapper = StateWrapperImpl::newObjectJavaArgs();
StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper);
cStateWrapper->state_ = shadowView.state;
}
local_ref<ReadableMap::javaobject> props =
castReadableMap(ReadableNativeMap::newObjectCxxArgs(shadowView.props->rawProps));
auto component = getPlatformComponentName(shadowView);
preallocateView(
javaUIManager_, surfaceId, shadowView.tag, component.get(), readableMap.get(), isLayoutableShadowNode);
javaUIManager_, surfaceId, shadowView.tag, component.get(), props.get(), (javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr), isLayoutableShadowNode);
}
void Binding::registerNatives() {
@@ -9,6 +9,7 @@ package com.facebook.react.fabric.mounting;
import android.view.View;
import androidx.annotation.UiThread;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewManagerRegistry;
import java.util.WeakHashMap;
@@ -26,13 +27,13 @@ public final class ContextBasedViewPool implements ViewFactory {
@UiThread
void createView(ThemedReactContext context, ReactStylesDiffMap props, String componentName) {
getViewPool(context).createView(componentName, props, context);
getViewPool(context).createView(componentName, props, null, context);
}
@UiThread
@Override
public View getOrCreateView(String componentName, ReactStylesDiffMap props, ThemedReactContext context) {
return getViewPool(context).getOrCreateView(componentName, props, context);
public View getOrCreateView(String componentName, ReactStylesDiffMap props, StateWrapper stateWrapper, ThemedReactContext context) {
return getViewPool(context).getOrCreateView(componentName, props, stateWrapper, context);
}
@UiThread
@@ -170,11 +170,12 @@ public class MountingManager {
}
@UiThread
public void createViewWithProps(
public void createView(
ThemedReactContext themedReactContext,
String componentName,
int reactTag,
@Nullable ReadableMap props,
@Nullable StateWrapper stateWrapper,
boolean isLayoutable) {
if (mTagToViewState.get(reactTag) != null) {
return;
@@ -183,19 +184,20 @@ public class MountingManager {
View view = null;
ViewManager viewManager = null;
ReactStylesDiffMap diffMap = null;
ReactStylesDiffMap propsDiffMap = null;
if (props != null) {
diffMap = new ReactStylesDiffMap(props);
propsDiffMap = new ReactStylesDiffMap(props);
}
if (isLayoutable) {
viewManager = mViewManagerRegistry.get(componentName);
view = mViewFactory.getOrCreateView(componentName, diffMap, themedReactContext);
view = mViewFactory.getOrCreateView(componentName, propsDiffMap, stateWrapper, themedReactContext);
view.setId(reactTag);
}
ViewState viewState = new ViewState(reactTag, view, viewManager);
viewState.mCurrentProps = diffMap;
viewState.mCurrentProps = propsDiffMap;
viewState.mCurrentState = (stateWrapper != null ? stateWrapper.getState() : null);
mTagToViewState.put(reactTag, viewState);
}
@@ -313,6 +315,7 @@ public class MountingManager {
String componentName,
int reactTag,
@Nullable ReadableMap props,
@Nullable StateWrapper stateWrapper,
boolean isLayoutable) {
if (mTagToViewState.get(reactTag) != null) {
@@ -320,7 +323,7 @@ public class MountingManager {
"View for component " + componentName + " with tag " + reactTag + " already exists.");
}
createViewWithProps(reactContext, componentName, reactTag, props, isLayoutable);
createView(reactContext, componentName, reactTag, props, stateWrapper, isLayoutable);
}
@UiThread
@@ -362,10 +365,10 @@ public class MountingManager {
final int mReactTag;
final boolean mIsRoot;
@Nullable final ViewManager mViewManager;
public ReactStylesDiffMap mCurrentProps;
public ReadableMap mCurrentLocalData;
public ReadableMap mCurrentState;
public EventEmitterWrapper mEventEmitter;
public ReactStylesDiffMap mCurrentProps = null;
public ReadableMap mCurrentLocalData = null;
public ReadableMap mCurrentState = null;
public EventEmitterWrapper mEventEmitter = null;
private ViewState(int reactTag, @Nullable View view, @Nullable ViewManager viewManager) {
this(reactTag, view, viewManager, false);
@@ -8,11 +8,13 @@ package com.facebook.react.fabric.mounting;
import android.view.View;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.uimanager.ThemedReactContext;
import javax.annotation.Nullable;
public interface ViewFactory {
View getOrCreateView(String componentName, ReactStylesDiffMap props, ThemedReactContext context);
View getOrCreateView(String componentName, @Nullable ReactStylesDiffMap props, @Nullable StateWrapper stateWrapper, ThemedReactContext context);
void recycle(ThemedReactContext context, String componentName, View view);
@@ -9,8 +9,10 @@ package com.facebook.react.fabric.mounting;
import androidx.annotation.UiThread;
import android.view.View;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewManagerRegistry;
import javax.annotation.Nullable;
public class ViewManagerFactory implements ViewFactory {
@@ -23,8 +25,8 @@ public class ViewManagerFactory implements ViewFactory {
@UiThread
@Override
public View getOrCreateView(
String componentName, ReactStylesDiffMap props, ThemedReactContext context) {
return mViewManagerRegistry.get(componentName).createViewWithProps(context, props, null);
String componentName, @Nullable ReactStylesDiffMap props, @Nullable StateWrapper stateWrapper, ThemedReactContext context) {
return mViewManagerRegistry.get(componentName).createView(context, props, stateWrapper, null);
}
@UiThread
@@ -10,6 +10,7 @@ import androidx.annotation.UiThread;
import android.view.View;
import com.facebook.react.common.ClearableSynchronizedPool;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.uimanager.ViewManagerRegistry;
@@ -26,20 +27,20 @@ public final class ViewPool {
}
@UiThread
void createView(String componentName, ReactStylesDiffMap props, ThemedReactContext context) {
void createView(String componentName, ReactStylesDiffMap props, StateWrapper stateWrapper, ThemedReactContext context) {
ClearableSynchronizedPool<View> viewPool = getViewPoolForComponent(componentName);
ViewManager viewManager = mViewManagerRegistry.get(componentName);
// TODO: T31905686 Integrate / re-implement jsResponder
View view = viewManager.createViewWithProps(context, props, null);
View view = viewManager.createView(context, props, stateWrapper, null);
viewPool.release(view);
}
@UiThread
View getOrCreateView(String componentName, ReactStylesDiffMap props, ThemedReactContext context) {
View getOrCreateView(String componentName, ReactStylesDiffMap props, StateWrapper stateWrapper, ThemedReactContext context) {
ClearableSynchronizedPool<View> viewPool = getViewPoolForComponent(componentName);
View view = viewPool.acquire();
if (view == null) {
createView(componentName, props, context);
createView(componentName, props, stateWrapper, context);
view = viewPool.acquire();
}
return view;
@@ -32,7 +32,7 @@ public class CreateMountItem implements MountItem {
@Override
public void execute(MountingManager mountingManager) {
mountingManager.createViewWithProps(mContext, mComponent, mReactTag, null, mIsLayoutable);
mountingManager.createView(mContext, mComponent, mReactTag, null, null, mIsLayoutable);
}
@Override
@@ -13,6 +13,7 @@ import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.fabric.mounting.MountingManager;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.uimanager.ThemedReactContext;
/** {@link MountItem} that is used to pre-allocate views for JS components. */
@@ -22,6 +23,7 @@ public class PreAllocateViewMountItem implements MountItem {
private final int mRootTag;
private final int mReactTag;
private final @Nullable ReadableMap mProps;
private final @Nullable StateWrapper mStateWrapper;
private final ThemedReactContext mContext;
private final boolean mIsLayoutable;
@@ -31,11 +33,13 @@ public class PreAllocateViewMountItem implements MountItem {
int reactTag,
String component,
@Nullable ReadableMap props,
StateWrapper stateWrapper,
boolean isLayoutable) {
mContext = context;
mComponent = component;
mRootTag = rootTag;
mProps = props;
mStateWrapper = stateWrapper;
mReactTag = reactTag;
mIsLayoutable = isLayoutable;
}
@@ -45,7 +49,7 @@ public class PreAllocateViewMountItem implements MountItem {
if (DEBUG) {
FLog.d(TAG, "Executing pre-allocation of: " + toString());
}
mountingManager.preallocateView(mContext, mComponent, mReactTag, mProps, mIsLayoutable);
mountingManager.preallocateView(mContext, mComponent, mReactTag, mProps, mStateWrapper, mIsLayoutable);
}
@Override
@@ -8,7 +8,6 @@
package com.facebook.react.uimanager;
import android.content.res.Resources;
import android.os.Build;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
@@ -19,7 +18,6 @@ import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.PopupMenu;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.R;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
@@ -256,7 +254,7 @@ public class NativeViewHierarchyManager {
try {
ViewManager viewManager = mViewManagers.get(className);
View view = viewManager.createViewWithProps(themedContext, null, mJSResponderHandler);
View view = viewManager.createView(themedContext, null, null, mJSResponderHandler);
mTagsToViews.put(tag, view);
mTagsToViewManagers.put(tag, viewManager);
@@ -11,10 +11,8 @@ import android.content.Context;
import android.view.View;
import com.facebook.react.bridge.BaseJavaModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.touch.JSResponderHandler;
import com.facebook.react.touch.ReactInterceptingViewGroup;
import com.facebook.react.uimanager.annotations.ReactProp;
@@ -41,6 +39,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
*
* @param viewToUpdate
* @param props
* @param stateWrapper
*/
public void updateProperties(@Nonnull T viewToUpdate, ReactStylesDiffMap props) {
ViewManagerPropertyUpdater.updateProps(this, viewToUpdate, props);
@@ -53,17 +52,18 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
private final @Nonnull T createView(
@Nonnull ThemedReactContext reactContext,
JSResponderHandler jsResponderHandler) {
return this.createViewWithProps(reactContext, null, jsResponderHandler);
return createView(reactContext, null, null, jsResponderHandler);
}
/**
* Creates a view with knowledge of props.
*/
public @Nonnull T createViewWithProps(
public @Nonnull T createView(
@Nonnull ThemedReactContext reactContext,
ReactStylesDiffMap props,
@Nullable ReactStylesDiffMap props,
@Nullable StateWrapper stateWrapper,
JSResponderHandler jsResponderHandler) {
T view = createViewInstanceWithProps(reactContext, props);
T view = createViewInstance(reactContext, props, stateWrapper);
addEventEmitters(reactContext, view);
if (view instanceof ReactInterceptingViewGroup) {
((ReactInterceptingViewGroup) view).setOnInterceptTouchEventListener(jsResponderHandler);
@@ -115,7 +115,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
* Override it if you need props upon creation of the view.
* @param reactContext
*/
protected @Nonnull T createViewInstanceWithProps(@Nonnull ThemedReactContext reactContext, ReactStylesDiffMap initialProps) {
protected @Nonnull T createViewInstance(@Nonnull ThemedReactContext reactContext, @Nullable ReactStylesDiffMap initialProps, @Nullable StateWrapper stateWrapper) {
T view = createViewInstance(reactContext);
if (initialProps != null) {
updateProperties(view, initialProps);