Understanding ViewTreeObserver leak

Try to change your code that removes the listener to run before the View is actually detached from the window, like this:

@Override public void onDetachedFromWindow() {
    scrollView.getViewTreeObserver().removeOnScrollChangedListener(scrollViewChangeListener);
    super.onDetachedFromWindow();
}

The reason is that after being detached from a window, getViewTreeObserver() returns a different instance (the "floating tree observer"), so you are not gonna remove your listener from the same object where you added it.


UPDATE

Since you are using a ViewTreeObserver of a child view, the behavior is slightly more complex and one possible solution would involve adding an OnAttachStateChangeListener to your scrollView and add/remove your OnScrollChangedListener from there.

Anyway in regard of the reason why there was a leak: getViewTreeObserver() is not going to return the same instance after the View has been detached from the window. Calling removeOnScrollChangedListener() may have no effect, keeping your original OnScrollChangedListener still attached to the old ViewTreeObserver, and so leaking your Context.