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).
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…