2

I'm getting the above error when calling finish() and then re-opening the app. Here's the code that manages navigation onBackPressed().

        android.app.FragmentManager settingsFragmentManager = getFragmentManager();
        FragmentManager fragmentManager = getSupportFragmentManager();

        if (settingsFragmentManager.getBackStackEntryCount() > 0)
            settingsFragmentManager.popBackStackImmediate();
        else if (fragmentManager.getBackStackEntryCount() > 0)
            fragmentManager.popBackStackImmediate();        

        if (fragmentManager.getBackStackEntryCount() == 0 && endIfEmpty) finish();
        if (fragmentManager.getBackStackEntryCount() == 0 && !endIfEmpty) loadView(0);
        if (fragmentManager.getBackStackEntryCount() == 0 && !userHasLoggedIn)
        {
            LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(loginBroadcastReceiver);
            finish();
        }

The method loadView calls is in charge of adding a fragment, based on what the user selected. When it is invoked with 0 as argument, it adds the default fragment.

This the method:

    private void loadView(int position)
    {   
        FragmentManager fragmentManager = getSupportFragmentManager();
        Bundle fragmentArgs = new Bundle();

        if (drawerOpened)
            mDrawerLayout.closeDrawer(drawerHolderLayout);

        switch (position) {
        case 0:
            ProfileEditFragment activityList = new ProfileEditFragment();

            fragmentArgs.clear();
            fragmentArgs.putString(ProfileEditFragment.ARG_AGENT_ID, String.valueOf(prefClass.getAgentId()));
            fragmentArgs.putString(ProfileEditFragment.ARG_USERNAME, prefClass.getUsername());
            fragmentArgs.putString(ProfileEditFragment.ARG_PASSWORD, prefClass.getHashedPassword());
            fragmentArgs.putInt(ProfileEditFragment.ARG_OPERATION, ProfileEditFragment.LOAD_ALL_DATA);

            activityList.setArguments(fragmentArgs);
            fragmentManager.beginTransaction().add(R.id.main_activity_content, activityList).addToBackStack(null).commit();
            //activityList.retrieveActivityFromServer(ProfileEditFragment.LOAD_ALL_DATA);

            break;
        }
    }

The exception occurrs when this line is executed:

fragmentManager.beginTransaction().add(R.id.main_activity_content, activityList).addToBackStack(null).commit();

However, this exception does not occurr when the app is launched for the FIRST TIME. It only appears when it is re-launched after a call to finish(). It is worth mentioning that the first fragment added is a LoginFragment. Once the login process is done, popBackstack is invoked, the backstack becomes empty and loadView(0) is called. So, why does it crash with the exception when the loadView is called but doesn't when LoginFragment is added?

Thanks in advance.

Jorge Cespedes
  • 547
  • 1
  • 11
  • 21
  • please read this http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html – Pavel Dudka Feb 02 '15 at 22:51
  • Thanks for replyin, I've read Alex Lockwood's post before, which is why I'm doing transactions inside onPostResume. As I said, the first time I launch the app everything works great. LoginFragment is added, login completes without error, popBackStack is called, it becomes empty and ActivityFragment is added without issues. But if the user leaves the app (finish() is called) and then re-opens it, LoginFragment is added, popBackStack is called, it becomes empty and the exception occurrs when I try to add ActivityFragment. Why can I add LoginFragment this second time, but not ActivityFragment? – Jorge Cespedes Feb 02 '15 at 23:07
  • I'm going through the same issue right now. I've read Alex Lockwood's posts but they don't seem to apply for my circumstance. I'm only seeing the issue if I back out and come back in from my Facebook login/register Activity. Still looking into it... – Tommy Visic Feb 06 '15 at 21:35
  • @TommyVisic if you see this please contact me on skype: phiter_fernandes. I need to talk to you about a game you made years ago. – Phiter Jan 07 '17 at 03:24

2 Answers2

1

In my case I opened a DialogFragment after an application moved to a background.

You can emulate this state this way: open a request, run Thread.sleep(2000), quickly press "Power off" on smartphone (or press "Menu" button), then "Power on" (or open the application). If a request brings error and DialogFragment shows, it will write in log: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState, corresponding line is dialogFragment.show(supportFragmentManager, TAG).

I tried a solution https://stackoverflow.com/a/22414366/2914140, it works fine, but contains this bug. So, add one more check:

if (supportFragmentManager?.isStateSaved == false) {
    dialogFragment.show(supportFragmentManager, TAG)
}

In this case after turning off a screen and turning on you simply won't see this dialog (sad to say), but your application won't crash.

UPDATE

Sorry, the old answer is outdated. See On showing dialog i get "Can not perform this action after onSaveInstanceState".

public class CustomDialogFragment extends DialogFragment {

    @Override
    public void show(FragmentManager manager, String tag) {
        try {
            FragmentTransaction ft = manager.beginTransaction();
            ft.add(this, tag);
            ft.commit();
        } catch (IllegalStateException e) {
        }
    }
}

In this case the dialog fragment will be shown.

CoolMind
  • 26,736
  • 15
  • 188
  • 224
0

Are you sure the Fragment commit is occurring on the Activity instance that you think it is?

I'm not sure if my situation applies to you, but I did have similar symptoms in that I'd only see the exception after stopping and restarting an Activity. I also found that Alex Lockwood's (very excellent) article on the subject didn't seem to help me, just like you mentioned in the comments.

Anyway I eventually realized I caused this exception by initializing a long-living object (a Facebook session object in my case) and providing it a reference to the Activity for callbacks. I'd only initialize the session object if Session.getActiveSession() indicated that a session was unavailable. This meant that the second time I started the Activity, the session from the previous Activity would be used, along with its callback that points to the previous Activity. The previous Activity had since been destroyed and had its onSaveInstanceState. When the callback was triggered, the old Activity would try to get its Fragment on, and boom, the exception occurred. I had been wracking my brain trying to figure out why I was getting this exception when the new Activity was in a valid state for a Fragment commit, but all along I was trying to commit a Fragment to an old, since-destroyed Activity.

You might not be using Facebook sessions per se, but perhaps you're doing something similar with a long-living object?

Good luck!

E.T.
  • 125
  • 1
  • 2
  • 11
Tommy Visic
  • 373
  • 2
  • 7