Skip to content

Commit

Permalink
Fix fragment leak in Material NavigationView
Browse files Browse the repository at this point in the history
Need to unregister the ViewTreeObserver, which was previously registered on the top-most View in the entire hierarchy.

PiperOrigin-RevId: 268532017
  • Loading branch information
Material Design Team authored and dsn5ft committed Oct 3, 2019
1 parent 4f771b2 commit 8555310
Showing 1 changed file with 33 additions and 19 deletions.
52 changes: 33 additions & 19 deletions lib/java/com/google/android/material/navigation/NavigationView.java
Expand Up @@ -27,6 +27,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
Expand Down Expand Up @@ -108,6 +109,7 @@ public class NavigationView extends ScrimInsetsFrameLayout {
private final int[] tmpLocation = new int[2];

private MenuInflater menuInflater;
private OnGlobalLayoutListener onGlobalLayoutListener;

public NavigationView(@NonNull Context context) {
this(context, null);
Expand Down Expand Up @@ -650,33 +652,45 @@ private ColorStateList createDefaultColorStateList(int baseColorThemeAttr) {
});
}

@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (Build.VERSION.SDK_INT < 16) {
getViewTreeObserver().removeGlobalOnLayoutListener(onGlobalLayoutListener);
} else {
getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
}
}

/**
* Add a listener to wait for layout changes so we can determine the location on screen. Based on
* the location we'll try to be smart about showing the scrim at under the status bar and under
* the system nav only when we should.
*/
private void setupInsetScrimsListener() {
onGlobalLayoutListener = new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
getLocationOnScreen(tmpLocation);
boolean isBehindStatusBar = tmpLocation[1] == 0;
presenter.setBehindStatusBar(isBehindStatusBar);
setDrawTopInsetForeground(isBehindStatusBar);

Context context = getContext();
if (context instanceof Activity && VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
boolean isBehindSystemNav =
((Activity) context).findViewById(android.R.id.content).getHeight()
== getHeight();
boolean systemNavNotFullyTransparent =
((Activity) context).getWindow().getNavigationBarColor() == Color.TRANSPARENT;
setDrawBottomInsetForeground(isBehindSystemNav && !systemNavNotFullyTransparent);
}
}
};

getViewTreeObserver()
.addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
getLocationOnScreen(tmpLocation);
boolean isBehindStatusBar = tmpLocation[1] == 0;
presenter.setBehindStatusBar(isBehindStatusBar);
setDrawTopInsetForeground(isBehindStatusBar);

Context context = getContext();
if (context instanceof Activity && VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
boolean isBehindSystemNav =
((Activity) context).findViewById(android.R.id.content).getHeight()
== getHeight();
boolean systemNavNotFullyTransparent =
((Activity) context).getWindow().getNavigationBarColor() == Color.TRANSPARENT;
setDrawBottomInsetForeground(isBehindSystemNav && !systemNavNotFullyTransparent);
}
}
});
onGlobalLayoutListener);
}

/** Listener for handling events on navigation items. */
Expand Down

0 comments on commit 8555310

Please sign in to comment.