Retained Fragments with UI and memory leaks

android, android-fragments, memory-leaks

Solution

In a `Fragment` with UI you often save some `View`s as instance state to speed up access. For example a link to your `EditText` so you don't have to `findViewById` it all the time.

The problem is that a `View` keeps a reference to the `Activity` context. Now if you retain a `View` you also retain a reference to that context.

That is no problem if the context is still valid but the typical retain case is restarting the Activity. Very often for a screen rotation for example. Activity recreation will create a new context and old contexts are intended to be garbage collected. But it can't be garbage collected now since your `Fragment` still has a reference to the old one.

Following example shows how not to do it

public class LeakyFragment extends Fragment {

    private View mLeak; // retained

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mLeak = inflater.inflate(R.layout.whatever, container, false);
        return mLeak;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        // not cleaning up.
    }
}

To get rid of that problem, you need to clear all references to your UI in `onDestroyView`. Once the `Fragment` instance is re-used you will be asked to create a new UI on `onCreateView`. There is also no point in keeping the UI after `onDestroyView`. The Ui is not going to be used.

The fix in this example is just changing `onDestroyView` to

@Override
public void onDestroyView() {
    super.onDestroyView();
    mLeak = null; // now cleaning up!
}

And besides keeping references to `View`s you should obviously not keep references to the `Activity` (e.g. from `onAttach` - clean on `onDetach`) or any `Context` (unless it's the `Application` context).

Problem

I've read that setting `.setOnRetainInstance(true)` on fragments presenting UI may lead to memory leaks. Could somebody please explain why and how this would happen? I didn't find a detailed explanation anywhere.

Original source

Related problems