mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Prototype View recycling for View
Summary: Prototype of View Recycling for View + generic APIs. Changelog: [Added][Android] Adding experimental View Recycling for Fabric on Android. Reviewed By: mdvacca Differential Revision: D36608419 fbshipit-source-id: c469ce2fe12ef9332d3def591118befc4a619870
This commit is contained in:
1 parent
0ef73f2a82
commit
7b778fbebb
9 files changed
+293
-11
No files matched your search
@@ -16,13 +16,16 @@ import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.common.mapbuffer.MapBuffer;
|
||||
import com.facebook.react.config.ReactFeatureFlags;
|
||||
import com.facebook.react.touch.JSResponderHandler;
|
||||
import com.facebook.react.touch.ReactInterceptingViewGroup;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
|
||||
import com.facebook.yoga.YogaMeasureMode;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Class responsible for knowing how to create and update catalyst Views of a given type. It is also
|
||||
@@ -33,6 +36,30 @@ import java.util.Map;
|
||||
public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
extends BaseJavaModule {
|
||||
|
||||
/**
|
||||
* For View recycling: we store a Stack of unused, dead Views. This is null by default, and when
|
||||
* null signals that View Recycling is disabled. `enableViewRecycling` must be explicitly called
|
||||
* in a concrete constructor to enable View Recycling per ViewManager.
|
||||
*/
|
||||
private HashMap<Integer, Stack<T>> mRecyclableViews = null;
|
||||
|
||||
/** Call in constructor of concrete ViewManager class to enable. */
|
||||
protected void enableViewRecycling() {
|
||||
if (ReactFeatureFlags.enableViewRecycling) {
|
||||
mRecyclableViews = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable Stack<T> getRecyclableViewStack(int surfaceId) {
|
||||
if (mRecyclableViews == null) {
|
||||
return null;
|
||||
}
|
||||
if (!mRecyclableViews.containsKey(surfaceId)) {
|
||||
mRecyclableViews.put(surfaceId, new Stack<>());
|
||||
}
|
||||
return mRecyclableViews.get(surfaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the vast majority of ViewManagers, you will not need to override this. Only override this
|
||||
* if you really know what you're doing and have a very unique use-case.
|
||||
@@ -137,7 +164,13 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
@NonNull ThemedReactContext reactContext,
|
||||
@Nullable ReactStylesDiffMap initialProps,
|
||||
@Nullable StateWrapper stateWrapper) {
|
||||
T view = createViewInstance(reactContext);
|
||||
T view = null;
|
||||
@Nullable Stack<T> recyclableViews = getRecyclableViewStack(reactContext.getSurfaceId());
|
||||
if (recyclableViews != null && !recyclableViews.empty()) {
|
||||
view = recycleView(reactContext, recyclableViews.pop());
|
||||
} else {
|
||||
view = createViewInstance(reactContext);
|
||||
}
|
||||
view.setId(reactTag);
|
||||
addEventEmitters(reactContext, view);
|
||||
if (initialProps != null) {
|
||||
@@ -157,7 +190,27 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
* Called when view is detached from view hierarchy and allows for some additional cleanup by the
|
||||
* {@link ViewManager} subclass.
|
||||
*/
|
||||
public void onDropViewInstance(@NonNull T view) {}
|
||||
public void onDropViewInstance(@NonNull T view) {
|
||||
@Nullable
|
||||
Stack<T> recyclableViews =
|
||||
getRecyclableViewStack(((ThemedReactContext) view.getContext()).getSurfaceId());
|
||||
// By default we treat views as recyclable
|
||||
if (recyclableViews != null) {
|
||||
recyclableViews.push(prepareToRecycleView((ThemedReactContext) view.getContext(), view));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a View is removed from the hierachy. This should be used to reset any properties.
|
||||
*/
|
||||
protected T prepareToRecycleView(@NonNull ThemedReactContext reactContext, @NonNull T view) {
|
||||
return view;
|
||||
}
|
||||
|
||||
/** Called when a View is going to be reused. */
|
||||
protected T recycleView(@NonNull ThemedReactContext reactContext, @NonNull T view) {
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can override this method to install custom event emitters on the given View. You
|
||||
@@ -370,4 +423,24 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
* components support setting padding, the default implementation of this method does nothing.
|
||||
*/
|
||||
public void setPadding(T view, int left, int top, int right, int bottom) {}
|
||||
|
||||
/**
|
||||
* Lifecycle method: called when a surface is stopped. Currently only used for View Recycling
|
||||
* cleanup. There is no corresponding startSurface lifecycle event for ViewManagers because we
|
||||
* currently only need this for recycling cleanup. Only called in Fabric.
|
||||
*/
|
||||
public void onSurfaceStopped(int surfaceId) {
|
||||
if (mRecyclableViews != null) {
|
||||
mRecyclableViews.remove(surfaceId);
|
||||
}
|
||||
}
|
||||
|
||||
/** With even slight memory pressure, we immediately evict all recyclable Views. */
|
||||
/* package */ void trimMemory() {
|
||||
// Wipe out all existing recyclable Views, but do not disable View Recycling entirely.
|
||||
// We only take any action if View Recycling is already enabled.
|
||||
if (mRecyclableViews != null) {
|
||||
mRecyclableViews = new HashMap<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user