简体   繁体   中英

Memory leak when I replace a Fragment

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM