diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index 56250e3cbc1bc41895760fe581b1712351a4dd29..a2f13160eb010d820e63eeb4ec86aa789bc0c2bf 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -851,6 +851,17 @@ public class FlutterActivity extends Activity // No-op. Hook for subclasses. } + /** + * Hook for the host to cleanup references that were established in + * {@link #configureFlutterEngine(FlutterEngine)} before the host is destroyed or detached. + *

+ * This method is called in {@link #onDestroy()}. + */ + @Override + public void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine) { + // No-op. Hook for subclasses. + } + /** * Hook for subclasses to control whether or not the {@link FlutterFragment} within this * {@code Activity} automatically attaches its {@link FlutterEngine} to this {@code Activity}. diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index 506a2894780b256d43ab10efbe785bcef425ef5b..9176ad6f5486dc2a3186d846263cbd491e3e2d07 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -421,6 +421,10 @@ import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; Log.v(TAG, "onDetach()"); ensureAlive(); + // Give the host an opportunity to cleanup any references that were created in + // configureFlutterEngine(). + host.cleanUpFlutterEngine(flutterEngine); + if (host.shouldAttachEngineToActivity()) { // Notify plugins that they are no longer attached to an Activity. Log.d(TAG, "Detaching FlutterEngine from the Activity that owns this Fragment."); @@ -693,6 +697,12 @@ import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; */ void configureFlutterEngine(@NonNull FlutterEngine flutterEngine); + /** + * Hook for the host to cleanup references that were established in + * {@link #configureFlutterEngine(FlutterEngine)} before the host is destroyed or detached. + */ + void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine); + /** * Returns true if the {@link FlutterEngine}'s plugin system should be connected to the * host {@link Activity}, allowing plugins to interact with it. diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterEngineConfigurator.java b/shell/platform/android/io/flutter/embedding/android/FlutterEngineConfigurator.java index 7ed15dd95a6641dec19c4373e53ba7b9f4f2d9a2..3f633c6c2e427a401a5494b7b25a0f29ce35b150 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterEngineConfigurator.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterEngineConfigurator.java @@ -30,4 +30,10 @@ public interface FlutterEngineConfigurator { * {@code Activity} at the time that this method is invoked. */ void configureFlutterEngine(@NonNull FlutterEngine flutterEngine); + + /** + * Cleans up references that were established in {@link #configureFlutterEngine(FlutterEngine)} + * before the host is destroyed or detached. + */ + void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine); } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index 3d274cbe2caf6e5f324394cbc1531806dc3e2456..6ad1037e3f4e01cb66a6f548ffbba1b30274f2da 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -924,6 +924,20 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm } } + /** + * Hook for the host to cleanup references that were established in + * {@link #configureFlutterEngine(FlutterEngine)} before the host is destroyed or detached. + *

+ * This method is called in {@link #onDetach()}. + */ + @Override + public void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine) { + FragmentActivity attachedActivity = getActivity(); + if (attachedActivity instanceof FlutterEngineConfigurator) { + ((FlutterEngineConfigurator) attachedActivity).cleanUpFlutterEngine(flutterEngine); + } + } + /** * See {@link NewEngineFragmentBuilder#shouldAttachEngineToActivity()} and * {@link CachedEngineFragmentBuilder#shouldAttachEngineToActivity()}. diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java index b6c72452a9cff66c9d50eea9458149876d4f50a4..ea24de453ee268499bf616720a94ee8121b195a3 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java @@ -550,6 +550,17 @@ public class FlutterFragmentActivity extends FragmentActivity // No-op. Hook for subclasses. } + /** + * Hook for the host to cleanup references that were established in + * {@link #configureFlutterEngine(FlutterEngine)} before the host is destroyed or detached. + *

+ * This method is called in {@link #onDestroy()}. + */ + @Override + public void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine) { + // No-op. Hook for subclasses. + } + /** * The path to the bundle that contains this Flutter app's resources, e.g., Dart code snapshots. *

diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java index 9adab515889546e1017736ef4626e1768a6395a5..953abb5a053e9e15893e3767523691071aa8611f 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java @@ -197,6 +197,21 @@ public class FlutterActivityAndFragmentDelegateTest { verify(mockHost, times(1)).configureFlutterEngine(mockFlutterEngine); } + @Test + public void itGivesHostAnOpportunityToCleanUpFlutterEngine() { + // ---- Test setup ---- + // Create the real object that we're testing. + FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); + + // --- Execute the behavior under test --- + // The FlutterEngine is created in onAttach(). + delegate.onAttach(RuntimeEnvironment.application); + delegate.onDetach(); + + // Verify that the host was asked to configure our FlutterEngine. + verify(mockHost, times(1)).cleanUpFlutterEngine(mockFlutterEngine); + } + @Test public void itSendsInitialRouteToFlutter() { // ---- Test setup ----