1

We have a method in Fragment that is used to retain Fragment in cases of orientation change when the Activity is destroyed and re-created again,

setRetainInstance(Boolean true/false)

How does it differentiate between when the Activity is re-created (destroyed and created again) and not fully destroyed?

Basically, I'm wondering how the Fragment knows when it has to be fully destroyed and when it has to be retained.

Ryan M
  • 18,333
  • 31
  • 67
  • 74
Gissipi_453
  • 1,250
  • 1
  • 25
  • 61
  • I saw this post as well. This doesn't answer my question. My question is about the internal workings and the how.. – Gissipi_453 Oct 22 '21 at 07:05
  • a) your question is not very clear. What is "not fully destroyed"? What do you mean the fragment "knows when it has to be fully destroyed"? b) Android is open source - any question about "how does the internals work" can be answered by reading the code for yourself. – dominicoder Oct 22 '21 at 08:32
  • Does this answer your question? [Understanding Fragment's setRetainInstance(boolean)](https://stackoverflow.com/questions/11182180/understanding-fragments-setretaininstanceboolean) – Adrian Mole Oct 22 '21 at 18:04
  • setRetainInstance() has been deprecated, how would we maneuver through this now if we wish t o save the instance of the fragment? – SlowLearnah Feb 27 '23 at 23:03

2 Answers2

2

Quite simply: it doesn't.

The retained Fragments are added to a ViewModel within the FragmentManager. When the Activity is recreated, the ViewModel is restored internally (as part of ComponentActivity) via the Activity's onRetainNonConfigurationInstance()/getLastNonConfigurationInstance() mechanism. If the Activity isn't being recreated, it and its non-configuration instance simply go away, and they're eventually cleaned up by the garbage collector.

Ryan M
  • 18,333
  • 31
  • 67
  • 74
  • But, if you don't use a ViewModel, SetRetainInstance of a Fragment will still work for Activity. What is a ViewModel doing here ? @Ryan M – Gissipi_453 Oct 22 '21 at 11:37
  • @Gissipi_453 That's just the internal implementation. The `Fragment` library is implemented on top of the ViewModel library, so it can take advantage of that functionality, even though you aren't explicitly using a `ViewModel` yourself. – Ryan M Oct 22 '21 at 11:39
  • Fragment on Android is there from ages, ViewModel is there from like last 5 years only. I don't think I agree with this – Gissipi_453 Oct 22 '21 at 12:44
  • 1
    @Gissipi_453 It's been rewritten on top of ViewModel (by my coworkers on the Android Toolkit team). You can read [the code](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java;l=89?q=fragmentmanager&sq=) yourself to verify (search for `FragmentManagerViewModel`). – Ryan M Oct 22 '21 at 12:46
  • 1
    All of this, by the way, assumes you're talking about [androidx Fragments](https://developer.android.com/reference/androidx/fragment/app/Fragment). If you're using the android.support or framework Fragments...well, you should switch, because they're a lot buggier. – Ryan M Oct 22 '21 at 12:48
  • Thanks Ryan for this valuable information. I was not aware of it – Gissipi_453 Oct 22 '21 at 16:06
0

Ryan's answer gave you the pointers, but you have to read the source:


    /**
     * Control whether a fragment instance is retained across Activity
     * re-creation (such as from a configuration change). If set, the fragment
     * lifecycle will be slightly different when an activity is recreated:
     * <ul>
     * <li> {@link #onDestroy()} will not be called (but {@link #onDetach()} still
     * will be, because the fragment is being detached from its current activity).
     * <li> {@link #onCreate(Bundle)} will not be called since the fragment
     * is not being re-created.
     * <li> {@link #onAttach(Activity)} and {@link #onActivityCreated(Bundle)} <b>will</b>
     * still be called.
     * </ul>
     *
     * @param retain <code>true</code> to retain this fragment instance across configuration
     *               changes, <code>false</code> otherwise.
     *
     * @see #getRetainInstance()
     * @deprecated Instead of retaining the Fragment itself, use a non-retained Fragment and keep
     * retained state in a ViewModel attached to that Fragment. The ViewModel's constructor and
     * its onCleared() callback provide the signal for initial creation and final destruction of
     * the retained state.
     */
    @Deprecated
    public void setRetainInstance(boolean retain) {
        FragmentStrictMode.onSetRetainInstanceUsage(this);
        mRetainInstance = retain;
        if (mFragmentManager != null) {
            if (retain) {
                mFragmentManager.addRetainedFragment(this);
            } else {
                mFragmentManager.removeRetainedFragment(this);
            }
        } else {
            mRetainInstanceChangedWhileDetached = true;
        }
    }

(source: cs.android.com)

In other words, the FragmentManager has a list of retained fragments. So it knows which fragments must be retained.

Needless to say but using setRetainInstance(true) has been deprecated; it is preferred to save whatever state you were trying to retain in a ViewModel that will survive a configuration change (among other things), and restore the state when/if the fragment is recreated.

About "why is this using a ViewModel if I'm not": Well you're free to not use a ViewModel, but the framework itself wouldn't want to pass on such a convenient opportunity to separate the concerns :)

Martin Marconcini
  • 26,875
  • 19
  • 106
  • 144