From 43114c4f7c9ca0c70c48c777dbd2957386d539e5 Mon Sep 17 00:00:00 2001 From: conradchen Date: Thu, 24 Feb 2022 08:29:05 -0800 Subject: [PATCH] [BottomSheet] Fix activity leak when setting states on destroying activities The activity leak can happen in a corner case: setting bottom sheet state when the bottom sheet is dismissed and the host activity is closed. In this situation SettleRunnable will be posted to ViewRootImpl since the bottom sheet is not attached, which leaves references of the dismissed bottom sheet (and thus the destroyed activity) in ViewRootImpl and causes activity leak. Fixes this by using weak reference in SettleRunnable instead of the strong reference, which is the standard practice of the BottomSheetBehavior class. Resolves https://github.com/material-components/material-components-android/issues/1417 PiperOrigin-RevId: 430709002 --- .../material/bottomsheet/BottomSheetBehavior.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java b/lib/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java index 3b1463f5b0a..6f3e66f4eb7 100644 --- a/lib/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java +++ b/lib/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java @@ -1592,7 +1592,7 @@ void startSettlingAnimation( settleRunnable = new SettleRunnable(child, state); } // If the SettleRunnable has not been posted, post it with the correct state. - if (settleRunnable.isPosted == false) { + if (!settleRunnable.isPosted) { settleRunnable.targetState = state; ViewCompat.postOnAnimation(child, settleRunnable); settleRunnable.isPosted = true; @@ -1890,21 +1890,23 @@ public int getLastStableState() { private class SettleRunnable implements Runnable { - private final View view; + private final WeakReference viewRef; private boolean isPosted; @State int targetState; SettleRunnable(View view, @State int targetState) { - this.view = view; + this.viewRef = new WeakReference<>(view); this.targetState = targetState; } @Override public void run() { - if (viewDragHelper != null && viewDragHelper.continueSettling(true)) { - ViewCompat.postOnAnimation(view, this); + if (viewRef.get() != null + && viewDragHelper != null + && viewDragHelper.continueSettling(true)) { + ViewCompat.postOnAnimation(viewRef.get(), this); } else { setStateInternal(targetState); }