I have just started to use LeakCanary and when I replace a Fragment, every time leaks increase. This is the LeakCanary report:
android.widget.LinearLayout instance
Leaking: YES (ObjectWatcher was watching this because com.home.app1.PostFragment received Fragment#onDestroyView() callback
(references to its views should be cleared to prevent leaks))
This is my Fragment Replace code:
public void change(Fragment fragment) {
((FragmentActivity) context).getSupportFragmentManager().beginTransaction()
.replace(R.id.frameLayout, fragment, "fragment")
.setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.addToBackStack(null)
.commit();
}
So I research on SO and some people say views must be clenead in onDestroyView
. Then I tried this in onDestroyView
: fragmentView=null;
but nothing was changed. Also tried this:
if (view.getParent() != null) {
((ViewGroup) view.getParent()).removeView(view);
}
But again nothing was changed. So I tried to make all views null like below:
@Override
public void onDestroyView() {
super.onDestroyView();
backButton=null;
swipeLayout=null;
imageView=null; ...etc.
}
Eventually leaking warnings on LeakCanary disappeared. But I think this is not a solution and does not make sense because there may be many views. So what's the solution to avoid this leaks? Thanks.
So I tried to make all views null like below
Eventually leaking warnings on LeakCanary disappeared.
You've found the solution - you were holding onto View
references (your backButton
, swipeLayout
, imageView
, etc.) after they were removed and supposed to be destroyed (onDestroyView
). Since holding a reference to them prevents them from being garbage collected, that's a memory leak.
But I think this is not a solution and does not make sense because there may be many views. So what's the solution to avoid this leaks?
If you're storing View
s in member variables manually, that's the best solution. You could use findViewById
to find it every time, but I wouldn't recommend it because you'll incur a performance penalty from repeatedly traversing the View hierarchy.
You can avoid both of those problems by using the View Binding feature of the Android development tooling. With that, you'll just have one Binding object to get rid of.
You could also use Butter Knife to manage your View variables for you - see the unbinder.unbind();
pattern mentioned on that page.