From c027f05ef48b3980c726c78a28117ad79750b8b1 Mon Sep 17 00:00:00 2001 From: Felix Oghina Date: Thu, 3 Mar 2016 11:11:21 -0800 Subject: [PATCH] add generic memory pressure listener interface Reviewed By: lexs Differential Revision: D2989071 fb-gh-sync-id: 375c7551bd4b281096850732432f016c2684add0 shipit-source-id: 375c7551bd4b281096850732432f016c2684add0 --- .../facebook/react/MemoryPressureRouter.java | 32 +++++++++++++------ .../react/ReactInstanceManagerImpl.java | 4 +-- .../react/bridge/CatalystInstance.java | 4 +-- .../react/bridge/MemoryPressureListener.java | 15 +++++++++ 4 files changed, 40 insertions(+), 15 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressureListener.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java b/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java index 58f283311..c209bef26 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java +++ b/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java @@ -2,7 +2,9 @@ package com.facebook.react; -import javax.annotation.Nullable; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; import android.annotation.TargetApi; import android.app.Activity; @@ -11,9 +13,8 @@ import android.content.Context; import android.content.res.Configuration; import android.os.Build; -import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.MemoryPressure; -import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.MemoryPressureListener; import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE; @@ -27,7 +28,8 @@ public class MemoryPressureRouter { // am start -a "com.facebook.catalyst.ACTION_TRIM_MEMORY" --activity-single-top -n private static final String ACTION_TRIM_MEMORY ="com.facebook.catalyst.ACTION_TRIM_MEMORY"; - private @Nullable CatalystInstance mCatalystInstance; + private final Set mListeners = + Collections.synchronizedSet(new LinkedHashSet()); private final ComponentCallbacks2 mCallbacks = new ComponentCallbacks2() { @Override public void onTrimMemory(int level) { @@ -60,12 +62,18 @@ public class MemoryPressureRouter { context.getApplicationContext().registerComponentCallbacks(mCallbacks); } - public void onNewReactContextCreated(ReactContext reactContext) { - mCatalystInstance = reactContext.getCatalystInstance(); + /** + * Add a listener to be notified of memory pressure events. + */ + public void addMemoryPressureListener(MemoryPressureListener listener) { + mListeners.add(listener); } - public void onReactInstanceDestroyed() { - mCatalystInstance = null; + /** + * Remove a listener previously added with {@link #addMemoryPressureListener}. + */ + public void removeMemoryPressureListener(MemoryPressureListener listener) { + mListeners.remove(listener); } public void destroy(Context context) { @@ -81,8 +89,12 @@ public class MemoryPressureRouter { } private void dispatchMemoryPressure(MemoryPressure level) { - if (mCatalystInstance != null) { - mCatalystInstance.handleMemoryPressure(level); + // copy listeners array to avoid ConcurrentModificationException if any of the listeners remove + // themselves in handleMemoryPressure() + MemoryPressureListener[] listeners = + mListeners.toArray(new MemoryPressureListener[mListeners.size()]); + for (MemoryPressureListener listener : listeners) { + listener.handleMemoryPressure(level); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java index faba27baf..56812d6ec 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java @@ -715,7 +715,7 @@ import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START catalystInstance.initialize(); mDevSupportManager.onNewReactContextCreated(reactContext); - mMemoryPressureRouter.onNewReactContextCreated(reactContext); + mMemoryPressureRouter.addMemoryPressureListener(catalystInstance); moveReactContextToCurrentLifecycleState(); for (ReactRootView rootView : mAttachedRootViews) { @@ -772,7 +772,7 @@ import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START } reactContext.destroy(); mDevSupportManager.onReactInstanceDestroyed(reactContext); - mMemoryPressureRouter.onReactInstanceDestroyed(); + mMemoryPressureRouter.removeMemoryPressureListener(reactContext.getCatalystInstance()); } /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java index 98ac8d763..17c01f542 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java @@ -21,7 +21,7 @@ import com.facebook.proguard.annotations.DoNotStrip; * Java APIs be invokable from JavaScript as well. */ @DoNotStrip -public interface CatalystInstance { +public interface CatalystInstance extends MemoryPressureListener { void runJSBundle(); // This is called from java code, so it won't be stripped anyway, but proguard will rename it, // which this prevents. @@ -48,8 +48,6 @@ public interface CatalystInstance { T getNativeModule(Class nativeModuleInterface); Collection getNativeModules(); - void handleMemoryPressure(MemoryPressure level); - /** * Adds a idle listener for this Catalyst instance. The listener will receive notifications * whenever the bridge transitions from idle to busy and vice-versa, where the busy state is diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressureListener.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressureListener.java new file mode 100644 index 000000000..e4640b96e --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressureListener.java @@ -0,0 +1,15 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.react.bridge; + +/** + * Listener interface for memory pressure events. + */ +public interface MemoryPressureListener { + + /** + * Called when the system generates a memory warning. + */ + void handleMemoryPressure(MemoryPressure level); + +}