Illegalstateexception When Replacing a Fragment

IllegalStateException when replacing a Fragment

I think you may have misunderstood my comment, so I'll offer a more detailed explanation here.

One problem that commonly arises with removing or replacing fragments is trying to remove a fragment that has been added to the layout through XML instead of programmatically in Java. This is not the same as inflating the fragment's own layout in the onCreateView() function of the fragment's Java code (this is what you seem to be describing in your response to my comment). To illustrate what I'm talking about, I'll show you two ways that people try to remove/replace fragments.

This is the Wrong Way to do it:

XML Layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

<fragment android:name="com.example.ExampleFragment"
android:id="@+id/example_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />

</LinearLayout>

Java:

swapFragment()
{
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}

This code, will not execute in the way that you expect. The initial fragment that is added in the XML layout will not be removed. This is because XML layouts are intended to describe static layout elements. You can change their contents at run time, or hide them, but you can't delete these things from the layout. This is what Dianne Hackborn was saying in the discussion thread I linked to before.

This is the right way to do it (At least in my experience):

XML Layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

<!-- Fragment will go here eventually, but it's not added in the layout -->

</LinearLayout>

Java:

protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);

ExampleFragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.fragment_container, newFragment);
transaction.commit();
}

...

swapFragment()
{
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}

This strategy does not add the fragment in the initial layout. Instead it adds it in the Java code when the Activity is created. This allows it to be removed from the layout (either using remove() or replace())

This might not solve your problem, but it is a common difficulty that Fragments create. You can make sure that you are adding the Fragments in the proper way to allow them to be removed, and then if that doesn't solve the problem we can troubleshoot further.

IllegalStateException when .replace fragment on restart

The FragmentManager is an

Interface for interacting with Fragment objects inside of an Activity.

It strikes me as a particular bad idea to have save it in a static field and reuse and old FragmentManager for a new activity. This will necessarily lead to Activity has been destroyed, when the new activity interact with the manager from the old activity.

In your code, replace

FragmentChange.getInstance(getFragmentManager());

by

new FragmentChange(getFragmentManager());

Replacing fragment in ViewPager causes IllegalStateException

To SWAP fragments in one tab of a View Pager you have to do it in a different way:

You need a fragment that goes in the ViewPager that acts as a container. which is managed by the ViewPager. This Fragment is allways there in the tab, never swaps or changes.

Inside that Fragment you have 2 child fragments that you can swap using transactions with the ChildFragmentManager. But the ViewPager doesn't even know about their existance.

How can I prevent java.lang.IllegalStateException: Fragment already added when replacing fragments?

I think I have successfully fixed this error, by trying to reproduce this in a simpler example:
https://stackoverflow.com/a/30672516/4107809

I was making a mistake where multiple instances of a fragment (not the VideoFragment) were added in successive calls to onCreate caused by recreation of the Activity. This fragment addition did not trigger the java.lang.IllegalStateException: Fragment already added because apparently this happens only if you try to add the same fragment instance more than once, not multiple instances of the same fragment.

Upon calling the fragment replace method, the java.lang.IllegalStateException: Fragment already added is generated for the new VideoFragment, even though the VideoFragment is only added once using replace.

By ensuring the different fragment was added only once, the replace by the VideoFragment no longer generates java.lang.IllegalStateException: Fragment already added: VideoFragment, at least for the steps for reproducing I outlined above. The IllegalStateException appears to have nothing to do with adding/replacing the VideoFragment, but with the state of the fragments being replaced.

I am displeased by this resolution for two reasons:

  1. The error message is misleading. It says the VideoFragment has already been added, and I have resolved this by making sure that a different fragment is not added more than once, which did not generate an exception.

  2. The replace documentation is very misleading. Based on my reading, it should not matter what the state of the fragment container is prior to calling to replace; the end state should be determined solely by the fragment that is added from the replace argument. I think this discrepancy is most clear in the linked question, though the answerer in that question disagrees.

Replace an existing fragment that was added to a container. This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.



Related Topics



Leave a reply



Submit