Files
react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java
yk3372 9dc0385405 fix memory leak
Summary:
Signed-off-by: yk3372 <yk3372@gmail.com>

What existing problem does the pull request solve?

ViewManagersPropertyCache, ViewManagerPropertyUpdater static field not release when ReactInstanceManager called destroy.

I use this url to integrate RN:
[http://facebook.github.io/react-native/docs/integration-with-existing-apps.html](http://facebook.github.io/react-native/docs/integration-with-existing-apps.html)
and in Activity's onDestroy function add the follow code to release RN:
```java
mReactInstanceManager.destroy();
mReactInstanceManager = null;
```
and then when I exit activity, find the static field not release.
the follow is screen shot:
before:
![2017-05-23 17 41 16](https://cloud.githubusercontent.com/assets/1514899/26350318/53ea250c-3fe5-11e7-8eda-a0dcc20ba4f6.jpg)
after:
![2017-05-23 17 38 49](https://cloud.githubusercontent.com/assets/1514899/26350329/5e5b273e-3fe5-11e7-9b0b-a8b0e044abf3.jpg)
Closes https://github.com/facebook/react-native/pull/14172

Differential Revision: D5128834

Pulled By: javache

fbshipit-source-id: 657763fa21fd8826b4060f9a17e7f35f0e1e04d3
2017-05-25 03:01:31 -07:00

166 lines
5.8 KiB
Java

// Copyright 2004-present Facebook. All Rights Reserved.
package com.facebook.react.uimanager;
import java.util.HashMap;
import java.util.Map;
import android.view.View;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
public class ViewManagerPropertyUpdater {
public interface Settable {
void getProperties(Map<String, String> props);
}
public interface ViewManagerSetter<T extends ViewManager, V extends View> extends Settable {
void setProperty(T manager, V view, String name, ReactStylesDiffMap props);
}
public interface ShadowNodeSetter<T extends ReactShadowNode> extends Settable {
void setProperty(T node, String name, ReactStylesDiffMap props);
}
private static final String TAG = "ViewManagerPropertyUpdater";
private static final Map<Class<?>, ViewManagerSetter<?, ?>> VIEW_MANAGER_SETTER_MAP =
new HashMap<>();
private static final Map<Class<?>, ShadowNodeSetter<?>> SHADOW_NODE_SETTER_MAP = new HashMap<>();
public static void clear() {
ViewManagersPropertyCache.clear();
VIEW_MANAGER_SETTER_MAP.clear();
SHADOW_NODE_SETTER_MAP.clear();
}
public static <T extends ViewManager, V extends View> void updateProps(
T manager,
V v,
ReactStylesDiffMap props) {
ViewManagerSetter<T, V> setter = findManagerSetter(manager.getClass());
ReadableMap propMap = props.mBackingMap;
ReadableMapKeySetIterator iterator = propMap.keySetIterator();
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
setter.setProperty(manager, v, key, props);
}
}
public static <T extends ReactShadowNode> void updateProps(T node, ReactStylesDiffMap props) {
ShadowNodeSetter<T> setter = findNodeSetter(node.getClass());
ReadableMap propMap = props.mBackingMap;
ReadableMapKeySetIterator iterator = propMap.keySetIterator();
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
setter.setProperty(node, key, props);
}
}
public static Map<String, String> getNativeProps(
Class<? extends ViewManager> viewManagerTopClass,
Class<? extends ReactShadowNode> shadowNodeTopClass) {
Map<String, String> props = new HashMap<>();
findManagerSetter(viewManagerTopClass).getProperties(props);
findNodeSetter(shadowNodeTopClass).getProperties(props);
return props;
}
private static <T extends ViewManager, V extends View> ViewManagerSetter<T, V> findManagerSetter(
Class<? extends ViewManager> managerClass) {
@SuppressWarnings("unchecked")
ViewManagerSetter<T, V> setter =
(ViewManagerSetter<T, V>) VIEW_MANAGER_SETTER_MAP.get(managerClass);
if (setter == null) {
setter = findGeneratedSetter(managerClass);
if (setter == null) {
setter = new FallbackViewManagerSetter<>(managerClass);
}
VIEW_MANAGER_SETTER_MAP.put(managerClass, setter);
}
return setter;
}
private static <T extends ReactShadowNode> ShadowNodeSetter<T> findNodeSetter(
Class<? extends ReactShadowNode> nodeClass) {
@SuppressWarnings("unchecked")
ShadowNodeSetter<T> setter = (ShadowNodeSetter<T>) SHADOW_NODE_SETTER_MAP.get(nodeClass);
if (setter == null) {
setter = findGeneratedSetter(nodeClass);
if (setter == null) {
setter = new FallbackShadowNodeSetter<>(nodeClass);
}
SHADOW_NODE_SETTER_MAP.put(nodeClass, setter);
}
return setter;
}
private static <T> T findGeneratedSetter(Class<?> cls) {
String clsName = cls.getName();
try {
Class<?> setterClass = Class.forName(clsName + "$$PropsSetter");
//noinspection unchecked
return (T) setterClass.newInstance();
} catch (ClassNotFoundException e) {
FLog.w(TAG, "Could not find generated setter for " + cls);
return null;
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Unable to instantiate methods getter for " + clsName, e);
}
}
private static class FallbackViewManagerSetter<T extends ViewManager, V extends View>
implements ViewManagerSetter<T, V> {
private final Map<String, ViewManagersPropertyCache.PropSetter> mPropSetters;
private FallbackViewManagerSetter(Class<? extends ViewManager> viewManagerClass) {
mPropSetters =
ViewManagersPropertyCache.getNativePropSettersForViewManagerClass(viewManagerClass);
}
@Override
public void setProperty(T manager, V v, String name, ReactStylesDiffMap props) {
ViewManagersPropertyCache.PropSetter setter = mPropSetters.get(name);
if (setter != null) {
setter.updateViewProp(manager, v, props);
}
}
@Override
public void getProperties(Map<String, String> props) {
for (ViewManagersPropertyCache.PropSetter setter : mPropSetters.values()) {
props.put(setter.getPropName(), setter.getPropType());
}
}
}
private static class FallbackShadowNodeSetter<T extends ReactShadowNode>
implements ShadowNodeSetter<T> {
private final Map<String, ViewManagersPropertyCache.PropSetter> mPropSetters;
private FallbackShadowNodeSetter(Class<? extends ReactShadowNode> shadowNodeClass) {
mPropSetters =
ViewManagersPropertyCache.getNativePropSettersForShadowNodeClass(shadowNodeClass);
}
@Override
public void setProperty(ReactShadowNode node, String name, ReactStylesDiffMap props) {
ViewManagersPropertyCache.PropSetter setter = mPropSetters.get(name);
if (setter != null) {
setter.updateShadowNodeProp(node, props);
}
}
@Override
public void getProperties(Map<String, String> props) {
for (ViewManagersPropertyCache.PropSetter setter : mPropSetters.values()) {
props.put(setter.getPropName(), setter.getPropType());
}
}
}
}