Prevent Fragment recovery in Android
Asked Answered
T

9

42

We are using Fragments and we don't need them to be automatically recovered when the Activity is recreated. But Android every time when Activity::onCreate(Bundle savedInstanceState) -> super.onCreate(savedInstanceState) is called, restores Fragments even if we use setRetainInstance(false) for those Fragments.

Moreover, in those Fragments Fragment.performCreateView() is called directly without going through Fragment::onAttach() and so on. Plus, some of the fields are null inside restored Fragment...

Does anybody know how to prevent Android from restoring fragments?

P.S. We know that in case of recreating Activity for config changes it could be done by adding to manifest android:configChanges="orientation|screenSize|screenLayout. But what about recreating activity in case of automatic memory cleaning?

Tadzhik answered 20/3, 2013 at 9:5 Comment(0)
T
59

We finished by adding to activity:

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

It suppresses any saved data on create/recreate cycle of an Activity and avoids fragments auto re-creation.

Tadzhik answered 28/3, 2013 at 13:34 Comment(9)
Simple yet so effective. This really saved my ass with a current bad design (1 Activity App + 1 Fragment per screen).Freighter
If the fragment has some UI then don't you think its a bad user experience.Expertize
This works like a charm, but I really hope there is a cleaner way of doing this...Takeoff
this make my app with ViewPager crashed.Seacock
And what method did it crash in?Tadzhik
It's a NullPointerException at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:569)‌​. I don't know from what method because It crash as soon as orientation changed and LogCat only show error from support library.Seacock
@momo, this is the same design I'm using - do you know a better approach?Brana
Those who got NPE with ViewPager when use this method, please override ViewPager.onRestoreInstanceState(Parcelable state) method and calling super.onRestoreInstanceState(null); instead.Bibliogony
I was already handling configuration changes but I now also use this solution to exploit API 24 multi-window support (android:resizeableActivity). My Activity creates multiple inter-dependent Fragments in it's onCreate(). These may or may not be created according to the re-sized/re-oriented window. This brilliant solution needs to be officially adopted and documented. In my case, the proposition by Android that it could sensibly re-create my Fragments was patently absurd.Esbenshade
F
24

@goRGon 's answer was very useful for me, but such use cause serious problems when there is some more information you needs to forward to your activity after recreate.

Here is improved version that only removes "fragments", but keep every other parameters.

ID that is removed from bundle is part of android.support.v4.app.FragmentActivity class as FRAGMENTS_TAG field. It may of course change over time, but it's not expected.

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

/**
 * Improve bundle to prevent restoring of fragments.
 * @param bundle bundle container
 * @return improved bundle with removed "fragments parcelable"
 */
private static Bundle createBundleNoFragmentRestore(Bundle bundle) {
    if (bundle != null) {
        bundle.remove("android:support:fragments");
    }
    return bundle;
}
Fusionism answered 27/9, 2016 at 10:44 Comment(2)
awesome. exactly what I was looking forDriscoll
You can also use the same technique in onSaveInstanceState(). This avoids persisting the Fragment information in the first place.Whaler
I
4

I was having a problem with TransactionTooLargeException. So thankfully after using tolargetool I founded that the fragments (android:support:fragments) were been in memory, and the transaction became too large. So finally I did this, and it worked great.

@Override
public void onSaveInstanceState(final Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable("android:support:fragments", null);
}

Edit: I added it to the Activity. In my case I have one single Activity app and Multiple Fragments.

Insane answered 28/1, 2019 at 19:11 Comment(2)
Sorry, did you add it to your activity or to fragments?Foist
@Foist I added it to the Activity. In my case I have one single Activity app and Multiple Fragments.Insane
B
3

Those who got NPE with ViewPager when use this method described in the accepted answer, please override

ViewPager.onRestoreInstanceState(Parcelable state)

method and call

super.onRestoreInstanceState(null);

instead.

Bibliogony answered 10/3, 2017 at 4:48 Comment(1)
this approach doesn't work with ViewPager2Optometry
N
1

I removed the fragments in Activity's onCreate.

Nilsanilsen answered 5/5, 2016 at 4:59 Comment(0)
W
0

For an app with a ViewPager, I remove the fragments in onCreate(), before their creation.

Based on this thread: Remove all fragments from container, we have:

FragmentManager fm = getSupportFragmentManager();
for (Fragment fragment: fm.getFragments()) {
  fm.beginTransaction().remove(fragment).commitNow();
}
Weldon answered 28/4, 2018 at 19:46 Comment(2)
This will cause an exception if fragments are configured to be restored.Matsumoto
How do you configure them to be restored?Weldon
E
0

Use this one for androidx

override fun onCreate(savedInstanceState: Bundle?) {
   preventFragmentRecreation()
   super.onCreate(savedInstanceState) 
}

private fun preventFragmentRecreation() {
   supportFragmentManager.addFragmentOnAttachListener { _, _ ->
            savedStateRegistry.unregisterSavedStateProvider("android:support:fragments")
        }
}
Eighteenth answered 24/8, 2022 at 9:56 Comment(0)
A
0

This worked for me

@Override
public void onSaveInstanceState(final Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.remove("androidx.lifecycle.BundlableSavedStateRegistry.key");
}
    
Amianthus answered 23/12, 2022 at 18:57 Comment(0)
D
-1

View hierarchy in not restored automatically. So, in Fragment.onCreateView() or Activity.onCreate(), you have to restore all views (from xml or programmatically). Each ViewGroup that contains a fragment, must have the same ID as when you created it the first time. Once the view hierarchy is created, Android restores all fragments and put theirs views in the right ViewGroup thanks to the ID. Let say that Android remembers the ID of the ViewGroup on which a fragment was. This happens somewhere between onCreateView() and onStart().

Discontinue answered 12/11, 2013 at 9:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.