From e34761ff25916c44b03fb370fa6146765e2b2495 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Sat, 6 Apr 2019 00:49:29 -0700 Subject: [PATCH] Android plumbing for State and LocalData update mount items Summary: Android plumbing for State and LocalData update mount items. See other commits in stack for usage Reviewed By: mdvacca Differential Revision: D14663522 fbshipit-source-id: 5604a6a9af292805e9ce46c68e5ce7472eef0218 --- .../react/fabric/FabricJSIModuleProvider.java | 3 ++ .../react/fabric/FabricUIManager.java | 9 ++++ .../react/fabric/jsi/StateWrapperImpl.java | 41 +++++++++++++++ .../facebook/react/fabric/jsi/jni/Binding.cpp | 51 +++++++++++++++++-- .../react/fabric/jsi/jni/NodeStateWrapper.cpp | 41 +++++++++++++++ .../react/fabric/jsi/jni/NodeStateWrapper.h | 32 ++++++++++++ .../facebook/react/fabric/jsi/jni/OnLoad.cpp | 2 + .../react/fabric/jsi/jni/StateWrapperImpl.cpp | 45 ++++++++++++++++ .../react/fabric/jsi/jni/StateWrapperImpl.h | 34 +++++++++++++ .../fabric/mounting/MountingManager.java | 24 +++++++++ .../mounting/mountitems/BatchMountItem.java | 2 +- .../mountitems/UpdateLocalDataMountItem.java | 1 - .../mountitems/UpdateStateMountItem.java | 31 +++++++++++ .../react/uimanager/StateWrapper.java | 29 +++++++++++ .../facebook/react/uimanager/ViewManager.java | 13 +++-- 15 files changed, 348 insertions(+), 10 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/StateWrapperImpl.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.cpp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.h create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.cpp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.h create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateStateMountItem.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/StateWrapper.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java index f095c3187..889f98d60 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java @@ -12,6 +12,7 @@ import com.facebook.react.fabric.jsi.ComponentRegistry; 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.ContextBasedViewPool; import com.facebook.react.fabric.mounting.LayoutMetricsConversions; import com.facebook.react.fabric.mounting.MountingManager; @@ -27,6 +28,7 @@ import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateLocalDataMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem; +import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.systrace.Systrace; @@ -111,6 +113,7 @@ public class FabricJSIModuleProvider implements JSIModuleProvider { ComponentRegistry.class.getClass(); EventBeatManager.class.getClass(); EventEmitterWrapper.class.getClass(); + StateWrapperImpl.class.getClass(); FabricSoLoader.class.getClass(); PreAllocateViewMountItem.class.getClass(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index cff4aed0d..433f2012f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -38,6 +38,7 @@ import com.facebook.react.fabric.jsi.Binding; 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.MountingManager; import com.facebook.react.fabric.mounting.mountitems.BatchMountItem; import com.facebook.react.fabric.mounting.mountitems.DeleteMountItem; @@ -50,8 +51,10 @@ import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateLocalDataMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem; +import com.facebook.react.fabric.mounting.mountitems.UpdateStateMountItem; import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.uimanager.ReactRootViewTagGenerator; +import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewManagerPropertyUpdater; import com.facebook.react.uimanager.ViewManagerRegistry; @@ -236,6 +239,12 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { return new UpdateLocalDataMountItem(reactTag, newLocalData); } + @DoNotStrip + @SuppressWarnings("unused") + private MountItem updateStateMountItem(int reactTag, Object stateWrapper) { + return new UpdateStateMountItem(reactTag, (StateWrapper) stateWrapper); + } + @DoNotStrip @SuppressWarnings("unused") private MountItem updateEventEmitterMountItem(int reactTag, Object eventEmitter) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/StateWrapperImpl.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/StateWrapperImpl.java new file mode 100644 index 000000000..b5f459f79 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/StateWrapperImpl.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + *

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.jsi; + +import android.annotation.SuppressLint; +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.NativeMap; +import com.facebook.react.bridge.ReadableNativeMap; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.uimanager.StateWrapper; + +/** + * This class holds reference to the C++ EventEmitter object. Instances of this class are created on + * the Bindings.cpp, where the pointer to the C++ event emitter is set. + */ +@SuppressLint("MissingNativeLoadLibrary") +public class StateWrapperImpl implements StateWrapper { + static { + FabricSoLoader.staticInit(); + } + + @DoNotStrip private final HybridData mHybridData; + + private static native HybridData initHybrid(); + + private StateWrapperImpl() { + mHybridData = initHybrid(); + } + + @Override public native ReadableNativeMap getState(); + public native void updateStateImpl(NativeMap map); + + @Override public void updateState(WritableMap map) { + updateStateImpl((NativeMap)map); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp index 0fd303f2c..6dfc081c8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp @@ -6,6 +6,7 @@ #include "AsyncEventBeat.h" #include "EventEmitterWrapper.h" #include "ReactNativeConfigHolder.h" +#include "StateWrapperImpl.h" #include #include @@ -276,6 +277,32 @@ local_ref createUpdateLocalData( castReadableMap(readableNativeMap).get()); } +local_ref createUpdateStateMountItem( + const jni::global_ref& javaUIManager, + const ShadowViewMutation& mutation) { + static auto updateStateInstruction = + jni::findClassStatic(UIManagerJavaDescriptor) + ->getMethod(jint, jobject)>( + "updateStateMountItem"); + + auto state = mutation.newChildShadowView.state; + + // We use state.get() to pass a raw pointer through the JNI + // We don't need to access the state ptr in Java, but we need to be able to + // pass a state object back through the JNI for state updates + + // Do not hold onto Java object from C + auto javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); + StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper); + cStateWrapper->state_ = state.get(); + + return updateStateInstruction( + javaUIManager, + mutation.newChildShadowView.tag, + javaStateWrapper.get()); +} + + local_ref createRemoveMountItem( const jni::global_ref& javaUIManager, const ShadowViewMutation& mutation) { @@ -351,6 +378,11 @@ void Binding::schedulerDidFinishTransaction( mountItems[position++] = createUpdateLocalData(javaUIManager_, mutation); } + if (mutation.oldChildShadowView.state != + mutation.newChildShadowView.state) { + mountItems[position++] = + createUpdateStateMountItem(javaUIManager_, mutation); + } auto updateLayoutMountItem = createUpdateLayoutMountItem(javaUIManager_, mutation); @@ -371,31 +403,42 @@ void Binding::schedulerDidFinishTransaction( } case ShadowViewMutation::Insert: { if (!isVirtual) { - mountItems[position++] = - createInsertMountItem(javaUIManager_, mutation); + // Insert item + mountItems[position++] = createInsertMountItem(javaUIManager_, mutation); + // Props if (mutation.newChildShadowView.props->revision > 1) { mountItems[position++] = createUpdatePropsMountItem(javaUIManager_, mutation); } + // LocalData + if (mutation.newChildShadowView.localData) { + mountItems[position++] = + createUpdateLocalData(javaUIManager_, mutation); + } + + // Layout auto updateLayoutMountItem = createUpdateLayoutMountItem(javaUIManager_, mutation); if (updateLayoutMountItem) { mountItems[position++] = updateLayoutMountItem; } - if (mutation.newChildShadowView.localData) { + // State + if (mutation.newChildShadowView.state) { mountItems[position++] = - createUpdateLocalData(javaUIManager_, mutation); + createUpdateStateMountItem(javaUIManager_, mutation); } } + // EventEmitter auto updateEventEmitterMountItem = createUpdateEventEmitterMountItem(javaUIManager_, mutation); if (updateEventEmitterMountItem) { mountItems[position++] = updateEventEmitterMountItem; } + break; } default: { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.cpp new file mode 100644 index 000000000..b75952fdc --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.cpp @@ -0,0 +1,41 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "NodeStateWrapper.h" +#include +#include + +using namespace facebook::jni; + +namespace facebook { +namespace react { + +jni::local_ref +NodeStateWrapper::initHybrid(jni::alias_ref) { + return makeCxxInstance(); +} + +jni::local_ref NodeStateWrapper::getState() { + folly::dynamic map = state_->getDynamic(); + local_ref readableNativeMap = + ReadableNativeMap::newObjectCxxArgs(map); + return readableNativeMap; +} + +void NodeStateWrapper::updateState(ReadableNativeMap* map) { + // Get folly::dynamic from map + auto dynamicMap = map->consume(); + // Set state + state_->updateState(dynamicMap); +} + +void NodeStateWrapper::registerNatives() { + registerHybrid({ + makeNativeMethod("getState", NodeStateWrapper::getState), + makeNativeMethod("updateState", NodeStateWrapper::updateState), + }); +} + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.h new file mode 100644 index 000000000..afa6af003 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.h @@ -0,0 +1,32 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include +#include +#include + +namespace facebook { +namespace react { + +class NodeStateWrapper : public jni::HybridClass { + public: + constexpr static const char* const kJavaDescriptor = + "Lcom/facebook/react/fabric/NodeStateWrapper;"; + + NodeStateWrapper() {} + + static void registerNatives(); + + jni::local_ref getState(); + void updateState(ReadableNativeMap* map); + + const State* state_; + private: + static jni::local_ref initHybrid(jni::alias_ref); +}; + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/OnLoad.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/OnLoad.cpp index 42c10f45f..be20e3fee 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/OnLoad.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/OnLoad.cpp @@ -9,12 +9,14 @@ #include "Binding.h" #include "EventBeatManager.h" #include "EventEmitterWrapper.h" +#include "StateWrapperImpl.h" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { return facebook::xplat::initialize(vm, [] { facebook::react::Binding::registerNatives(); facebook::react::EventBeatManager::registerNatives(); facebook::react::EventEmitterWrapper::registerNatives(); + facebook::react::StateWrapperImpl::registerNatives(); facebook::react::ComponentFactoryDelegate::registerNatives(); }); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.cpp new file mode 100644 index 000000000..1e5a2db6e --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.cpp @@ -0,0 +1,45 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "StateWrapperImpl.h" +#include +#include + +using namespace facebook::jni; + +namespace facebook { +namespace react { + +/** + * Called from Java constructor through the JNI. + */ +jni::local_ref +StateWrapperImpl::initHybrid(jni::alias_ref) { + return makeCxxInstance(); +} + +jni::local_ref StateWrapperImpl::getState() { + folly::dynamic map = state_->getDynamic(); + local_ref readableNativeMap = + ReadableNativeMap::newObjectCxxArgs(map); + return readableNativeMap; +} + +void StateWrapperImpl::updateStateImpl(NativeMap* map) { + // Get folly::dynamic from map + auto dynamicMap = map->consume(); + // Set state + state_->updateState(dynamicMap); +} + +void StateWrapperImpl::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", StateWrapperImpl::initHybrid), + makeNativeMethod("getState", StateWrapperImpl::getState), + makeNativeMethod("updateStateImpl", StateWrapperImpl::updateStateImpl), + }); +} + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.h new file mode 100644 index 000000000..0796f5ec8 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.h @@ -0,0 +1,34 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include +#include +#include + +namespace facebook { +namespace react { + +class Instance; + +class StateWrapperImpl : public jni::HybridClass { + public: + constexpr static const char* const kJavaDescriptor = + "Lcom/facebook/react/fabric/jsi/StateWrapperImpl;"; + + static void registerNatives(); + + jni::local_ref getState(); + void updateStateImpl(NativeMap *map); + + const State* state_; + private: + jni::alias_ref jhybridobject_; + + static jni::local_ref initHybrid(jni::alias_ref); +}; + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index 0ddd04879..dc143386b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -17,6 +17,7 @@ import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableNativeMap; import com.facebook.react.bridge.SoftAssertions; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.fabric.FabricUIManager; @@ -26,11 +27,13 @@ import com.facebook.react.uimanager.IllegalViewOperationException; import com.facebook.react.uimanager.ReactStylesDiffMap; import com.facebook.react.uimanager.RootView; import com.facebook.react.uimanager.RootViewManager; +import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManagerRegistry; import com.facebook.yoga.YogaMeasureMode; +import android.util.Log; import java.util.concurrent.ConcurrentHashMap; /** @@ -270,6 +273,26 @@ public class MountingManager { } } + @UiThread + public void updateState(final int reactTag, StateWrapper stateWrapper) { + UiThreadUtil.assertOnUiThread(); + ViewState viewState = getViewState(reactTag); + ReadableNativeMap newState = stateWrapper.getState(); + if (viewState.mCurrentState != null && viewState.mCurrentState.equals(newState)) { + return; + } + viewState.mCurrentState = newState; + + ViewManager viewManager = viewState.mViewManager; + + if (viewManager == null) { + throw new IllegalStateException("Unable to find ViewManager for tag: " + reactTag); + } + viewManager.updateState( + viewState.mView, + stateWrapper); + } + @UiThread public void preallocateView( ThemedReactContext reactContext, @@ -326,6 +349,7 @@ public class MountingManager { @Nullable final ViewManager mViewManager; public ReactStylesDiffMap mCurrentProps; public ReadableMap mCurrentLocalData; + public ReadableMap mCurrentState; public EventEmitterWrapper mEventEmitter; private ViewState(int reactTag, @Nullable View view, @Nullable ViewManager viewManager) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java index 73a3503b2..7a0000b26 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java @@ -45,7 +45,7 @@ public class BatchMountItem implements MountItem { @Override public void execute(MountingManager mountingManager) { Systrace.beginSection( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricUIManager::mountViews (" + mSize + " items)"); + Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricUIManager::mountViews - " + mSize + " items"); for (int mountItemIndex = 0; mountItemIndex < mSize; mountItemIndex++) { MountItem mountItem = mMountItems[mountItemIndex]; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLocalDataMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLocalDataMountItem.java index b6f334a91..0786e8f61 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLocalDataMountItem.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLocalDataMountItem.java @@ -8,7 +8,6 @@ package com.facebook.react.fabric.mounting.mountitems; import com.facebook.react.fabric.mounting.MountingManager; import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.ReadableNativeMap; public class UpdateLocalDataMountItem implements MountItem { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateStateMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateStateMountItem.java new file mode 100644 index 000000000..e1dee17a1 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateStateMountItem.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + *

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.StateWrapper; + +public class UpdateStateMountItem implements MountItem { + + private final int mReactTag; + private final StateWrapper mStateWrapper; + + public UpdateStateMountItem(int reactTag, StateWrapper stateWrapper) { + mReactTag = reactTag; + mStateWrapper = stateWrapper; + } + + @Override + public void execute(MountingManager mountingManager) { + mountingManager.updateState(mReactTag, mStateWrapper); + } + + @Override + public String toString() { + return "UpdateStateMountItem [" + mReactTag + "] - stateWrapper: " + mStateWrapper; + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/StateWrapper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/StateWrapper.java new file mode 100644 index 000000000..2f6ba96d8 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/StateWrapper.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + *

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 com.facebook.react.bridge.ReadableNativeMap; +import com.facebook.react.bridge.WritableMap; + +/** + * This is a wrapper that can be used for passing State objects from Fabric C++ + * core to platform-specific components in Java. + * State allows you to break out of uni-directional dataflow by calling updateState, + * which communicates state back to the C++ layer. + */ +public interface StateWrapper { + /** + * Get a ReadableNativeMap object from the C++ layer, which is a K/V map of + * string keys to values. + */ + ReadableNativeMap getState(); + + /** + * Pass a map of values back to the C++ layer. + */ + void updateState(WritableMap map); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java index 086c5b102..d3724a5e1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java @@ -13,6 +13,7 @@ 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; @@ -196,13 +197,17 @@ public abstract class ViewManager return ViewManagerPropertyUpdater.getNativeProps(getClass(), getShadowNodeClass()); } - /** - * - */ - public @Nullable Object updateLocalData(@Nonnull T view, ReactStylesDiffMap props, ReactStylesDiffMap localData) { + public @Nullable Object updateLocalData( @Nonnull T view, ReactStylesDiffMap props, ReactStylesDiffMap localData) { return null; } + /** + * Subclasses can implement this method to receive state updates shared between all instances + * of this component type. + */ + public void updateState(@Nonnull T view, StateWrapper stateWrapper) { + } + public long measure( ReactContext context, ReadableMap localData,