7

My FragmentActivity(singleTop) is giving me IllegalStateException if I try to switch the navigation tab in the onNewIntent method.

More specifically, My application use SherlockActionBar with three tabs, one tab is updated when a push notification is received (and the intent is called), if the App was suspended on another tab, when I receive the intent (in the onNewIntent) I change the tab (and therefore the fragment) to the third tab with bar.setSelectedNavigationItem() and this is causing me the problem. If the app was suspended on the third tab, no exception occurs.

Code:

@Override
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Bundle bundle = intent.getExtras();
        if (bundle != null) {
            bar.setSelectedNavigationItem(Utils.ORDER_STATUS_TAB_ID);
        } else {
        }
    } 

The push notification intent:

    Intent notificationIntent = new Intent(context,
            MainActivity.class);
    notificationIntent.putExtra("orderUpdate",
            new Gson().toJson(orderUpdate));
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
            | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
            notificationIntent, 0);

    notification.contentIntent = contentIntent;

The TabListener method (with the comment on the line 56 in the stacktrace)

@Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        ft = activity.getSupportFragmentManager().beginTransaction();
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        if (mFragment == null) {
            mFragment = Fragment
                    .instantiate(activity, mClass.getName(), mArgs);
            ft.add(android.R.id.content, mFragment, tag);
            ft.commit();
        } else {
            ft.attach(mFragment);
            ft.commit(); // line 56
        }

The detailed exception:

07-12 20:06:40.959: E/AndroidRuntime(8639): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
07-12 20:06:40.959: E/AndroidRuntime(8639):     at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1299)
07-12 20:06:40.959: E/AndroidRuntime(8639):     at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1310)
07-12 20:06:40.959: E/AndroidRuntime(8639):     at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:541)
07-12 20:06:40.959: E/AndroidRuntime(8639):     at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:525)
07-12 20:06:40.959: E/AndroidRuntime(8639):     at com.wizche.ui.MyTabListener.onTabSelected(MyTabListener.java:56)
07-12 20:06:40.959: E/AndroidRuntime(8639):     at com.actionbarsherlock.internal.app.ActionBarImpl.selectTab(ActionBarImpl.java:526)
07-12 20:06:40.959: E/AndroidRuntime(8639):     at com.actionbarsherlock.internal.app.ActionBarImpl.setSelectedNavigationItem(ActionBarImpl.java:317)
07-12 20:06:40.959: E/AndroidRuntime(8639):     at com.wizche.MainActivity.onNewIntent(MainActivity.java:205)
Wizche
  • 893
  • 13
  • 32

2 Answers2

11

I found a fix for this, kind of ugly anyway. I just switch the tab in the onResume instead of onNewIntent:

    @Override
    public void onResume() {
        super.onResume();
        if(switchToTab){
            bar.setSelectedNavigationItem(Utils.ORDER_STATUS_TAB_ID);
            switchToTab = false;
        }
     }

And in the onNewIntent() I just set the switchToTab = true. I hope someone will come with a better solution.

Wizche
  • 893
  • 13
  • 32
  • 1
    I had the very same issue. I was trying hard hacking the ActionBar.TabListener implementation, adding a ft.commitAllowingStateLoss(), however Sharlock it self will also call ft.commit(), it cannot be committed twice. I also tried the answer at http://stackoverflow.com/a/10261438/245345, but it won't help. Finally I found your solution, which works well. Thanks. – Evi Song Apr 30 '13 at 12:11
0

I think you should not call commit in onTabSelected method. It's done by the framework already.

Oh, and use the transaction you receive, don't create a new one.

 public void onTabSelected(Tab tab, FragmentTransaction ft) {
    //remove the first line
    //ft = activity.getSupportFragmentManager().beginTransaction();
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    if (mFragment == null) {
        mFragment = Fragment
                .instantiate(activity, mClass.getName(), mArgs);
        ft.add(android.R.id.content, mFragment, tag);
        //not sure about this one
        ft.commit();
    } else {
        ft.attach(mFragment);
        //not sure about this one neither
        ft.commit(); // line 56
    }
Snicolas
  • 37,840
  • 15
  • 114
  • 173
  • The TabListener was token from Google example so I suppose is correct. What you mean to use the transaction I receive? – Wizche Jul 12 '12 at 18:50
  • Thanks for the update, the getSupportFragmentManager() should be there to support multiple platform (I use the Support Library), if I remove the commit/beginTransaction it works in normal case but still give me the same exception on switch tab after resume. I assume I can't perform this action from the onNewIntent method because the FragmentManager isn't ready yet. – Wizche Jul 13 '12 at 14:10