12

I call popBackStack() in Activity onCreate() method, however I am getting the exception:

Caused by java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

android.app.FragmentManagerImpl.checkStateLoss (FragmentManager.java:1428)
android.app.FragmentManagerImpl.enqueueAction (FragmentManager.java:1446)
android.app.FragmentManagerImpl.popBackStack (FragmentManager.java:572)

I understand that one way of solving this exception, provided you are OK with the effects on the UI and end user, is to call commitAllowingStateLoss.

The problem is, with popBackStack there is no commit call. Is there some other way to call popBackStack and allow state loss?

I should say, I am doing this in onPostResume and getting this exception.

user3690202
  • 3,844
  • 3
  • 22
  • 36
  • i think this error is thrown when you call popBackStack() on an inactive activity. post your code to debug further – arjun Mar 04 '17 at 07:20
  • @arjun I call popBackStack from within onPostResume, which according to all references I could find was a safe place to be calling it after the app resumes. I can't post any more code because the application is huge, but it boils down to popBackStack being called within onPostResume. Surely there has to be some place where I can reinitialise the GUI after the app resumes safely?? – user3690202 Mar 04 '17 at 07:31
  • As suggested by @arjun, have you tried performing it in `onResumeFragments()`? – azizbekian Mar 04 '17 at 08:07
  • try applying !isFinishing() first before add/remove fragment – silentsudo Mar 04 '17 at 08:08
  • @azizbekian Activity doesn't have an onResumeFragments. FragmentActivity does, but that's not what I'm using. – user3690202 Mar 04 '17 at 09:21

3 Answers3

1

After much research I have come to the conclusion that it is not possible to manipulate fragments on Android when the Activity is resumed. I have tried, as per the mentioned blog post, onPostResume() and onResumeFragments() to pop fragments from the backstack, and both result in intermittent crashes when released to production.

The downside to this reality is that if you wanted to, for example, display an end of level fragment, followed by an interstitial advertisement, followed by the next level (as a different fragment to the end of level fragment) then it is not possible to use fragments.

For my personal situation, I removed all fragments from my application. I keep using layouts, because editing the UI in XML is useful, but the Fragment lifecycle is unusable in its current state so I rolled my own "fragment" subsystem, but better because it can be manipulated from the Activities onResume.

I hope that one day Google will fix this because it makes developing for Android really unpleasant. Anyway, if anyone needs to use fragments, but doesn't like the typical onSaveInstanceState exception that you will invariably get, here is my "GameScreen" implementation (it's like a fragment, only better)

/**
 * GameScreen
 */
public class GameScreen {

    private int id;
    private View view;
    private ViewGroup viewGroup;
    protected MainActivity mainActivity;

    public GameScreen(MainActivity mainActivity, int id) {
        this.mainActivity = mainActivity;
        this.id = id;
    }

    public void create(LayoutInflater layoutInflater, ViewGroup viewGroup) {
        this.viewGroup = viewGroup;
        view = layoutInflater.inflate(id, viewGroup, false);
        viewGroup.addView(view);
    }

    public void show() {
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            View v = viewGroup.getChildAt(i);
            if (v != view) {
                v.setVisibility(View.INVISIBLE);
            }
        }

        view.setVisibility(View.VISIBLE);
    }
}
user3690202
  • 3,844
  • 3
  • 22
  • 36
0

I got the below from this blog http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html

This error may throw if commit() is in any Activity callback which may be called before activity state is restored. So best place to do popBackStack() is onResumeFragments() callback

popBackStack() do have a commit() called internally as what it does is just reverse the last FragmentTransaction in backstack.

arjun
  • 3,514
  • 4
  • 27
  • 48
  • I'm not using FragmentActivity, only Activity. And that blog post (I've read it before) already __guarantees__ that doing this from within onPostResume() will work - which it clearly doesn't. Therefore that blog contains information that is fundamentally wrong. – user3690202 Mar 04 '17 at 09:20
  • but it is recommended to use `AppCombatActivity` which extends `FragamentActivity` where you can try using `onResumeFragments()` callback – arjun Mar 04 '17 at 09:33
  • Can you cite exactly where that is recommended? It certainly isn't the default base class generated when you create a new fragment activity project in Android Studio. – user3690202 Mar 04 '17 at 09:35
  • when you create a new activity in android studio it does create new activity only by extending `AppCombatActivity` – arjun Mar 04 '17 at 09:37
  • No, it didn't when I created this project. It generated: public class MainActivity extends Activity – user3690202 Mar 04 '17 at 09:40
  • ok. that is not a problem now. If it is not going to break anything in your code and if you are willing to, then you can use `AppCombatActivity` and check this if it can help you know about AppCombatActivity http://stackoverflow.com/q/29797172/2809326 – arjun Mar 04 '17 at 09:45
  • I don't want to use the app compat libraries, and I don't feel like I should need to. I'd need to change a lot of code to do that. There __must__ be a safe location to do GUI configuration in Android that works both at first-time startup and at resume from pause. This is insanity. – user3690202 Mar 04 '17 at 22:03
  • 1
    Using AppCompat makes the lifecycle more consistent across Android versions; it's not a bad idea to migrate all your code. – rds Mar 10 '17 at 19:31
  • 2
    @rds - Using the words Android, Lifecycle, and Consistent in the same sentence should be a crime :-) – user3690202 Mar 11 '17 at 02:41
  • If you won't be using the AppCompat libraries or any of the jetpack libraries, don't use fragments. I even thought they were deprecated at the OS level. – Joakim Engstrom May 05 '21 at 11:39
0

Check this method it could be helpful:

popBackStackImmediate()

The advantage of the noted method is that it returns a boolean value which indicates the success of the back stack. At least you can try-catch the method to prevent exception(s) & to find out why is it happening.

Take a look at this guidance:

https://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()