Friday, March 10, 2017

popBackStack and commitAllowingStateLoss

Leave a Comment

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.

2 Answers

Answers 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);     } } 

Answers 2

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.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment