androidfragmentmanager

How to prevent FragmentManager from being destroyed after rotation


When I click the show more button a new fragment opens. However if I rotate the device and then click it I get an error.

enter image description here

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.rekijan.initiativetrackersecondedition, PID: 4673
    java.lang.IllegalStateException: FragmentManager has been destroyed
        at androidx.fragment.app.FragmentManager.enqueueAction(FragmentManager.java:1878)
        at androidx.fragment.app.BackStackRecord.commitInternal(BackStackRecord.java:329)
        at androidx.fragment.app.BackStackRecord.commit(BackStackRecord.java:294)
        at com.rekijan.initiativetrackersecondedition.ui.activities.MainActivity.replaceCharacterDetailFragment(MainActivity.java:207)
        at com.rekijan.initiativetrackersecondedition.character.adapter.CharacterAdapter$2.onClick(CharacterAdapter.java:305)
        at android.view.View.performClick(View.java:7448)
        at android.view.View.performClickInternal(View.java:7425)
        at android.view.View.access$3600(View.java:810)
        at android.view.View$PerformClick.run(View.java:28305)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

So the code is in a RecyclerViewAdapter

holder.showCharacterDetailButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ((MainActivity)context).replaceCharacterDetailFragment(holder.getAdapterPosition());
            }
        });

And then in MainActivity

public void replaceCharacterDetailFragment(int position) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (getResources().getBoolean(R.bool.isTablet)) {
            transaction.replace(R.id.second_fragment_container, CharacterDetailFragment.newInstance(position));
            transaction.commit();
        } else {
            transaction.replace(R.id.main_fragment_container, CharacterDetailFragment.newInstance(position));
            transaction.addToBackStack(null);
            transaction.commit();
            //Enable the back button in action bar
            if (getSupportActionBar() != null) getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            AppExtension app = (AppExtension) this.getApplicationContext();
            app.setShowBackNavigation(true);
        }
    }

More code can be found in github becuase open source yay https://github.com/ej-krielen/pf2initiativetracker

A common given 'solution' is to use isDestroyed or isFinishing. Sure the app doesn't crash if I use that but then the fragment is also not being made.

So to reiterate:


Solution

  • Right sometimes when updating an old project you forget your own logic. The problem was that in my adapter I use a reference to context. The adapter however is created in the AppExtension so on a recreate of the Activity this wasn't being set again. So now when the Activity gets recreated I pass the context to the adapter again and it all works fine.