简体   繁体   中英

Fragment Rotation Crash issue in Android

I've got a very temperamental android application that I'm working on.

I've got a navigation drawer that swaps fragments depending on what the user has selected.

However, when the screen is rotated the app crashes with this error:

java.lang.RuntimeException: Unable to destroy activity {MainActivity}: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

My fragments all extend a base class 'BaseFragment':

    public class BaseFragment  extends Fragment{
    protected FragmentManager fragmentManager;

    public void setFragmentManager(FragmentManager fragmentManager){
        this.fragmentManager=fragmentManager;
    }
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
    }
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Fragment f = (Fragment) fragmentManager
                .findFragmentById(R.id.container);
        if (f != null)
            fragmentManager.beginTransaction().remove(f).commit();
    }

}

My default fragment 'NewsFeedFragment' looks like this:

    public class NewsFeedFragment extends BaseFragment{

    /**
     * Returns a new instance of this fragment for the given section
     * number.
     */
    public static NewsFeedFragment newInstance(int sectionNumber) {
        NewsFeedFragment fragment = new NewsFeedFragment();
        return fragment;
    }

    public NewsFeedFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        setFragmentManager(getFragmentManager());
        View rootView = inflater.inflate(R.layout.fragment_news_feed, container, false);;
        return rootView;
    }
}

My main activity looks like this:

    public class MainActivity extends BaseActivity {

    /**
     * Fragment managing the behaviors, interactions and presentation of the navigation drawer.
     */
    private NavigationDrawerFragment mNavigationDrawerFragment;

    /**
     * Used to store the last screen title. For use in {@link #restoreActionBar()}.
     */
    private CharSequence mTitle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.titlebar);
        ActionBar actionBar=getActionBar();

        mNavigationDrawerFragment = (NavigationDrawerFragment)
                getFragmentManager().findFragmentById(R.id.navigation_drawer);
        mTitle = getTitle();

        // Set up the drawer.
        mNavigationDrawerFragment.setUp(
                R.id.navigation_drawer,
                (DrawerLayout) findViewById(R.id.drawer_layout));

    }



    public void onSectionAttached(int number) {
        switch (number) {
            case 1:
                mTitle = getString(R.string.news_feed_activity);
                break;
            case 2:
                mTitle = getString(R.string.friends_activity);
                break;
            case 3:
                mTitle = getString(R.string.events_activity);
                break;
            case 4:
                mTitle = getString(R.string.locations_activity);
                break;
            case 5:
                mTitle = getString(R.string.settings_activity);
                break;
        }
    }

    public void restoreActionBar() {
        ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
        actionBar.setDisplayShowTitleEnabled(true);
        actionBar.setTitle("");
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if (!mNavigationDrawerFragment.isDrawerOpen()) {
            // Only show items in the action bar relevant to this screen
            // if the drawer is not showing. Otherwise, let the drawer
            // decide what to show in the action bar.
            getMenuInflater().inflate(R.menu.news_feed, menu);
            restoreActionBar();
            return true;
        }
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        //if (id == R.id.action_settings) {
        //    return true;
        //}
        return super.onOptionsItemSelected(item);
    }


}

As I say this error occurs ONLY ON ROTATION.

Here is the full error output stream:

 EXCEPTION: main
    Process: APP ID, PID: 8399
    java.lang.RuntimeException: Unable to destroy activity {MainActivity}: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
            at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3497)
            at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3515)
            at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3715)
            at android.app.ActivityThread.access$900(ActivityThread.java:135)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1202)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5017)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
            at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1323)
            at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1341)
            at android.app.BackStackRecord.commitInternal(BackStackRecord.java:597)
            at android.app.BackStackRecord.commit(BackStackRecord.java:575)
            at uk.co.stephen_robinson.uni.lufelf.NewsFeedFragment.onDestroyView(NewsFeedFragment.java:43)
            at android.app.Fragment.performDestroyView(Fragment.java:1898)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:954)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1062)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1044)
            at android.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:1881)
            at android.app.Activity.performDestroy(Activity.java:5402)
            at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1117)
            at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3484)
            at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3515)
            at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3715)
            at android.app.ActivityThread.access$900(ActivityThread.java:135)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1202)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5017)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)

I would really appreciate some help on this.

Thanks in advance,

James.

You get your error because you can't do this...

 @Override
    public void onDestroyView() {
        super.onDestroyView();
        Fragment f = (Fragment) fragmentManager
                .findFragmentById(R.id.container);
        if (f != null)
            fragmentManager.beginTransaction().remove(f).commit();
    }

...in the onDestroyView() function. Instead, you should remove the fragment in the onPause() method of the activity class. And, similarly, you should add the fragments in the activity's onResume() method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM