- Fix mounting of views when a re-order happen caused by changes in viewflattening

Summary:
This diff fixes a bug that is reproducible when a view is reordered in a different level of hierarchy in the react tree.
Even if this is not supported by react, this can still happen because of viewFlattening.

Reviewed By: shergin

Differential Revision: D14817452

fbshipit-source-id: 13425b0e6a280affe681e80b4a6daa17ee56251a
This commit is contained in:
David Vacca
2019-04-30 01:48:25 -07:00
committed by Facebook Github Bot
parent 8e6031cac7
commit f98880b1a3
3 changed files with 97 additions and 3 deletions
@@ -39,6 +39,7 @@ import com.facebook.react.fabric.jsi.EventBeatManager;
import com.facebook.react.fabric.jsi.EventEmitterWrapper;
import com.facebook.react.fabric.jsi.FabricSoLoader;
import com.facebook.react.fabric.jsi.StateWrapperImpl;
import com.facebook.react.fabric.mounting.mountitems.CreateMountItem;
import com.facebook.react.fabric.mounting.MountingManager;
import com.facebook.react.fabric.mounting.mountitems.BatchMountItem;
import com.facebook.react.fabric.mounting.mountitems.DeleteMountItem;
@@ -73,7 +74,6 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
public static final String TAG = FabricUIManager.class.getSimpleName();
public static final boolean DEBUG =
PrinterHolder.getPrinter().shouldDisplayLogMessage(ReactDebugOverlayTags.FABRIC_UI_MANAGER);
private static final Map<String, String> sComponentNames = new HashMap<>();
private static final int FRAME_TIME_MS = 16;
private static final int MAX_TIME_IN_FRAME_FOR_NON_BATCHED_OPERATIONS_MS = 8;
@@ -203,6 +203,21 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
}
}
@DoNotStrip
@SuppressWarnings("unused")
private MountItem createMountItem(
String componentName, int reactRootTag, int reactTag, boolean isLayoutable) {
String component = sComponentNames.get(componentName);
if (component == null) {
throw new IllegalArgumentException("Unable to find component with name " + componentName);
}
ThemedReactContext reactContext = mReactContextForRootTag.get(reactRootTag);
if (reactContext == null) {
throw new IllegalArgumentException("Unable to find ReactContext for root: " + reactRootTag);
}
return new CreateMountItem(reactContext, reactRootTag, reactTag, component, isLayoutable);
}
@DoNotStrip
@SuppressWarnings("unused")
private MountItem removeMountItem(int reactTag, int parentReactTag, int index) {
@@ -328,12 +328,37 @@ local_ref<JMountItem::javaobject> createDeleteMountItem(
return deleteInstruction(javaUIManager, mutation.oldChildShadowView.tag);
}
local_ref<JMountItem::javaobject> createCreateMountItem(
const jni::global_ref<jobject>& javaUIManager,
const ShadowViewMutation& mutation,
const Tag rootTag) {
static auto createJavaInstruction =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<alias_ref<JMountItem>(jstring, jint, jint, jboolean)>(
"createMountItem");
auto newChildShadowView = mutation.newChildShadowView;
local_ref<JString> componentName =
getPlatformComponentName(newChildShadowView);
jboolean isLayoutable = newChildShadowView.layoutMetrics != EmptyLayoutMetrics;
return createJavaInstruction(
javaUIManager,
componentName.get(),
rootTag,
newChildShadowView.tag,
isLayoutable);
}
void Binding::schedulerDidFinishTransaction(
MountingTransaction &&mountingTransaction) {
SystraceSection s("FabricUIManager::schedulerDidFinishTransaction");
auto telemetry = mountingTransaction.getTelemetry();
auto mutations = mountingTransaction.getMutations();
auto surfaceId = mountingTransaction.getSurfaceId();
std::vector<local_ref<jobject>> queue;
// Upper bound estimation of mount items to be delivered to Java side.
@@ -345,6 +370,7 @@ void Binding::schedulerDidFinishTransaction(
JArrayClass<JMountItem::javaobject>::newArray(size);
auto mountItems = *(mountItemsArray);
std::unordered_set<Tag> deletedViews;
int position = 0;
for (const auto& mutation : mutations) {
@@ -355,6 +381,14 @@ void Binding::schedulerDidFinishTransaction(
oldChildShadowView.layoutMetrics == EmptyLayoutMetrics;
switch (mutation.type) {
case ShadowViewMutation::Create: {
if (mutation.newChildShadowView.props->revision > 1
|| deletedViews.find(mutation.newChildShadowView.tag) != deletedViews.end()) {
mountItems[position++] =
createCreateMountItem(javaUIManager_, mutation, surfaceId);
}
break;
}
case ShadowViewMutation::Remove: {
if (!isVirtual) {
mountItems[position++] =
@@ -365,6 +399,8 @@ void Binding::schedulerDidFinishTransaction(
case ShadowViewMutation::Delete: {
mountItems[position++] =
createDeleteMountItem(javaUIManager_, mutation);
deletedViews.insert(mutation.oldChildShadowView.tag);
break;
}
case ShadowViewMutation::Update: {
@@ -407,8 +443,8 @@ void Binding::schedulerDidFinishTransaction(
// Insert item
mountItems[position++] = createInsertMountItem(javaUIManager_, mutation);
// Props
if (mutation.newChildShadowView.props->revision > 1) {
if (mutation.newChildShadowView.props->revision > 1 ||
deletedViews.find(mutation.newChildShadowView.tag) != deletedViews.end()) {
mountItems[position++] =
createUpdatePropsMountItem(javaUIManager_, mutation);
}
@@ -0,0 +1,43 @@
/**
* 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.fabric.mounting.mountitems;
import com.facebook.react.fabric.mounting.MountingManager;
import com.facebook.react.uimanager.ThemedReactContext;
public class CreateMountItem implements MountItem {
private final String mComponent;
private final int mRootTag;
private final int mReactTag;
private final ThemedReactContext mContext;
private final boolean mIsLayoutable;
public CreateMountItem(
ThemedReactContext context,
int rootTag,
int reactTag,
String component,
boolean isLayoutable) {
mContext = context;
mComponent = component;
mRootTag = rootTag;
mReactTag = reactTag;
mIsLayoutable = isLayoutable;
}
@Override
public void execute(MountingManager mountingManager) {
mountingManager.createViewWithProps(mContext, mComponent, mReactTag, null, mIsLayoutable);
}
@Override
public String toString() {
return "CreateMountItem [" + mReactTag + "]";
}
}