Activity's onDestroy / Fragment's onDestroyView set Null practices

30,341

So the reason it's different between Fragments and Activities is because their lifecycles are different. When an Activity is destroyed, it's going away for good. However, Fragments may create and destroy their views multiple times before they're actually destroyed. For clarification, in an Activity:

onDestroy()
onCreate()

will never happen in sequence for the same Activity instance. For a Fragment, the following is perfectly valid:

onCreate()
onCreateView()
onDestroyView()
onCreateView()
onDestroyView()
onDestroy()

One case where you can see this is when a Fragment goes into the back stack. Its view will be destroyed (as it is no longer visible) but the instance will remain around to be easily resumed when the user presses back to return to it (at which point onCreateView() will again be called).

After onDestroyView(), you can (and likely should) release all of your View references to allow them to be garbage collected. In many cases, it's not necessary, as if it's just happening during a configuration change, onDestroy() will immediately follow and the whole instance will be garbage collected.

Essentially, I would say it is good practice to release any and all view references in onDestroyView(), and could save quite a bit of memory if your app has a large backstack.

Share:
30,341
Admin
Author by

Admin

Updated on July 09, 2022

Comments

  • Admin
    Admin almost 2 years

    I am reading ListFragment source code and I see this implementation:

    ListAdapter mAdapter;
    ListView mList;
    View mEmptyView;
    TextView mStandardEmptyView;
    View mProgressContainer;
    View mListContainer;
    CharSequence mEmptyText;
    boolean mListShown;
    
    /**
     * Detach from list view.
     */
    @Override
    public void onDestroyView() {
        mHandler.removeCallbacks(mRequestFocus);
        mList = null;
        mListShown = false;
        mEmptyView = mProgressContainer = mListContainer = null;
        mStandardEmptyView = null;
        super.onDestroyView();
    }
    

    In this function, Google developers set Null to all view fields that declared in ListFragment and remove callback 'mRequestFocus'.

    In ListActivity source code. Google developers implemented like below:

    protected ListAdapter mAdapter;
    protected ListView mList;
    
    private Handler mHandler = new Handler();
    
    
    @Override
    protected void onDestroy() {
        mHandler.removeCallbacks(mRequestFocus);
        super.onDestroy();
    }
    

    I didn't see Google developers set Null to mList on onDestroy of ListActivity as they did for ListFragment class.

    My question is

    1. Why google developers didnot set Null to mList in onDestroy of ListActivity? Any reasons?

    2. Do we need to set Null to all View fields in Activity's onDestroy and Fragment's onDestroyView?

    3. Any practices for set Null in these two functions: Activity's onDestroy and Fragment's onDestroyView?

    Thank you for your ideas!

  • Admin
    Admin over 9 years
    How about leaking memory If I don't set Null?
  • Volodymyr Lykhonis
    Volodymyr Lykhonis over 9 years
    It is impossible, since all reference under fragment object, which means once fragment object is out, all views and others out too.
  • Kevin Coppock
    Kevin Coppock over 9 years
    @VladimirLichonos It's very possible, actually, especially if a Fragment has setRetainInstance(true) set on it. If you keep those view references around, you could easily leak an Activity instance (as Views retain a reference to the Activity).
  • Volodymyr Lykhonis
    Volodymyr Lykhonis over 9 years
    It is a weird use case when using Views and setRetainInstance. But again, it is based on logic of the fragment as I mentioned above.
  • Admin
    Admin over 9 years
    Very good explain. I have a question. Why google developers did Not set Null to mAdapter in ListFragment's onDestroyView. Setting Null to non-ui field such as mAdapter is unnecessary?
  • Kevin Coppock
    Kevin Coppock over 9 years
    It's a good question. Typically it wouldn't matter, but adapters tend to also hold a reference to an Activity context. I suppose it holds to the contract of the method, which is onDestroyVIEW, so they are only destroying the View references. I think it would be unexpected behavior if you called setListAdapter(), and then later on, you call getListAdapter() and it is inexplicably null. Since an adapter isn't an expensive object to keep hold of (except in the case of setRetainInstance() when it could leak an activity), there's not much benefit to releasing it.
  • j2emanue
    j2emanue about 7 years
    I wonder then if it's better approach to unbind in oncreateview just before you bind?
  • John Pang
    John Pang almost 6 years
    When you bind to new instances of (sub)view in onCreateView, that will unbind the old instances of (sub)views. Setting null right before assigning a new value is unneccesary.
  • the_prole
    the_prole over 2 years
    In Kotlin this would make the binding nullable forcing you to add the null safe operator to every call on the binding. Is there a ware around this, or does one just go ahead and add the operator to every call?
  • Kevin Coppock
    Kevin Coppock over 2 years
    For Kotlin, if you have many views, I'd recommend just writing a wrapper class to hold them (e.g. class ViewHolder(val view1: View, val view2: View)). Then, you only have one nullable wrapper to dereference.
  • Kahan Bhalani
    Kahan Bhalani over 2 years
    Is it necessary in Fragment to set the binding variable to null in onDestroyView()? If we don't set it to null, it will be replaced with a new instance in onCreateView() anyways.