103
FATAL EXCEPTION: main
Process: com.example.loan, PID: 24169
java.lang.IllegalStateException: Fragment already added: FormFragment{428f10c8 #1 id=0x7f050055 form}
    at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1192)
    at android.support.v4.app.BackStackRecord.popFromBackStack(BackStackRecord.java:722)
    at android.support.v4.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1533)
    at android.support.v4.app.FragmentManagerImpl$2.run(FragmentManager.java:489)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1484)
    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:450)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5068)
    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:792)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
    at dalvik.system.NativeStart.main(Native Method)

So, I have an android app that build with the tabhost. There are three tabs in total, in the tab2, there is a button to make the fragment transaction in tab2 (which is calling the function in the fragment activity)

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
        t.replace(R.id.realtabcontent, mFrag);
        t.addToBackStack(null);
        t.commit();

There is exception if I run like this:

  1. Inside the tab2, I press the button to change fragment
  2. Go to other tab (eg. tab 1 or tab 3)
  3. Press back button
  4. Throw exception

How to fix that? Thanks for helping

3

16 Answers 16

186

This happens when we try to add same fragment or DialogFragment twice before dismissing,

just call

if(mFragment.isAdded())
{
     return; //or return false/true, based on where you are calling from
}

Having said that, I don't see any reason why to remove old fragment and add the same fragment again since we can update the UI/data by simply passing parameters to the method inside the fragment

Sign up to request clarification or add additional context in comments.

6 Comments

This should be the accepted answer. The accepted answer makes no sense. First, there should be no negation of isAdded(). Second, in the comments, it is suggested that this code goes in onCreate(), which is also nonsensical. This line of code should be placed directly before the line where the fragment is added (or replaced), not in onCreate() or onCreateView(). It's too late to execute that code in either of those methods.
if(fragment.isAdded()) fragmentTransaction.show(fragment);
also must be checked for hiding fragments.
I need to add similar fragments and only attributes in the fragment are different. But duplicated error still occurs.
i had already implemented to check if fragment already added then return (the code of add fragment will not be executed) , as the my application is live on the play store still i got the crash fragment is already added from the some of the devices not all the devices i am trying to figure it out from the month ago, i can not over come it, i had applied numbers of solutions and update the build on the live play store, still i am receiving the error from the some of the devices like Galaxy S20+ 5G, huawei , there fewer devices that have the issue i got, any help would be appreciated thanks
|
17

Remove the old fragment in case it is still added and then add the new fragment:

FragmentManager fm = getSupportFragmentManager();
Fragment oldFragment = fm.findFragmentByTag("fragment_tag");
if (oldFragment != null) {
    fm.beginTransaction().remove(oldFragment).commit();
}
MyFragment newFragment = new MyFragment();
fm.beginTransaction().add(newFragment , "fragment_tag");

7 Comments

shouldn't we send arguments to make any changes to the already displayed fragment? instead of removing and adding it again
You cannot set the arguments after the fragment was added to the fragment manager. From docs: "This method cannot be called if the fragment is added to a FragmentManager and if isStateSaved() would return true." So you need to call your fragment methods directly if you want to update UI.
yes, I didn't mean setting via setArguments, was referring to sending arguments as params to update, so removing and adding the same fragment has no use right ?
It depends. If you need to reconfigure a lot of things it may be easier to just replace the fragment with a new one. It all depends of your needs.
I continue receiving the error, if use one transaction. Probably this is due to asynchronous behaviour of work with fragment manager.
|
10

You just have to check one condition in your fragment mentioned below:

if(!isAdded())
{
    return;
}

isAdded = Return true if the fragment is currently added to its activity. Taken from the official document. This will not add that fragment if it is already added

Check below link for a reference:
http://developer.android.com/reference/android/app/Fragment.html#isAdded()

7 Comments

thanks for your help, do you mean I put the if(!isAdded()) inside oncreateview?
Yes, you just have to put that code i have mentioned in my answer above...It means that your fragment is already added in the stack. So, no need to add it again and it returns simply.
this makes no sense, you cant return void in onCreateView, did you mean onCreate? i tried this in there and it didnt help my issue
Is this added to onCreate?
Why the negation sign? Shouldn't the fragment be added if !isAdded() ?
|
8

Sometimes it happens for not finding proper id from the respective layout. I faced this problem. Then after many hours I found that I set wrong recyclerview id. I change it, and works fine for me.

So, double check your fragment layout.

3 Comments

Thanks, it was the same for me. The exception message couldn't be more misleading.
After more than one month for investigating the root cause, This was the reason. Thanks a lot
Thanks, this was the issue, and it is absurd that the exception message lead us all here just to find out that the view id was wrong.
8

You just have to check one condition before start fragment transaction

 if (!fragmentOne.isAdded()){
            transaction = manager.beginTransaction();
            transaction.add(R.id.group,fragmentOne,"Fragment_One");
            transaction.commit();
 }

this is working perfactly for me...

Comments

2

Here my solution for Dialog Fragment (you can use this concept also for fragment class)

I have try to click show dialog fragment by tap button multiple time and quickly.

FragmentManager fm = getSupportFragmentManager();
Fragment oldFragment = fm.findFragmentByTag("wait_modal");

if(oldFragment != null && oldFragment.isAdded())
    return;

if(oldFragment == null 
    && !please_wait_modal.isAdded() 
    && !please_wait_modal.isVisible()) {
    fm.executePendingTransactions();
    please_wait_modal.show(fm, "wait_modal");
}

Comments

1

You can try this:

 if (dialogFolderGallery.isAdded()) {
                dialogFolderGallery.dismiss();
            } else { //bla...bla..
}

Comments

1

I have this error when not wrapping my body XML inside a ViewGroup inside FrameLayout.

Error:

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".screens.home.HomeEpoxyFragment">

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swipe_refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv"
            android:overScrollMode="never"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</FrameLayout>

Solved:

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".screens.home.HomeEpoxyFragment">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv"
                android:overScrollMode="never"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>

</FrameLayout>

Hope this may help someone.

Comments

0

For me it works like:

Fragment oldFragment = manager.findFragmentByTag(READER_VIEW_POPUP);
if (oldFragment != null) {
    manager.beginTransaction().remove(oldFragment).commit();
}

FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();

Comments

0

It even can occur if in FragmentStatePagerAdapter of your ViewPager you create an item that already exists:

override fun getItem(position: Int): Fragment {
    return tabs[0] // Right variant: tabs[position]
}

(private val tabs: List<Fragment> is a list of fragments in tabs).

6 Comments

How did you solve this? It's very similar to my use-case
@Mitch, I wrote return tabs[position] in the second line.
I'm also using the same concept as return tabs[position] but it still throws an error
@Mitch, sorry, I don't know without a code. For general case currently I use stackoverflow.com/a/57161814/2914140. Do you think FragmentStatePagerAdapter throws the error in getItem?
It's very likely to be the source of the error since it's where the instance(s) of the fragment(s) shown by the ViewPager are retrieved
|
0

To my surprise, I made stupid mistake by calling the fragment transaction twice:

if (!FirebaseManager.isClientA && !FirebaseManager.isClientB) {
      fragment = new FragmentA();
      getFragmentManager().beginTransaction().add(R.id.fragment_frame, fragment, null).addToBackStack("").commit();
} else if (FirebaseManager.isClientB) {
      fragment = new FragmentB();
} else {
      fragment = new FragmentC();
}
getFragmentManager().beginTransaction().add(R.id.fragment_frame, fragment, null).addToBackStack("").commit();

Make sure you don't make the same mistake.

Comments

0

Add Fragment as below

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
    t.replace(R.id.realtabcontent, mFrag);
    t.addToBackStack(null);
    t.commitNowAllowingStateLoss();

4 Comments

What will happen with old and new fragments? Will it replace old with new?
No, it will not replace it will add the previous fragment to back stack.
I wonder, is it possible? Yesterday I tried similar code and got an error, see stackoverflow.com/questions/38566628/…, because addToBackStack is not allowed together with commitNow.
In that link, he is manually disabling the back stack. With addToBackStack it will enable to manage back stack of fragment
0

I got this error when incorrectly used my ViewModel inside of Fragment like this:

//This is wrong!
MyViewModel viewModel = new MyViewModel(getActivity().getApplication());

Correct way:

viewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication())).get(MyViewModel.class);

Comments

0

not good solving, but it work)

if(!ConfirmDataSync.isVisible) show()

Comments

0

Fragment transactions are asynchronous.

It is possible that you have two or more calls to this code before the fragment transactions are executed. !selectPlan04Dialog.isVisible() & !selectPlan04Dialog.isAdded() condition is true and show() schedules another fragment transaction to execute later.

Some options for fixing this:

  • Create a new dialog every time and don't try to reuse an old one
  • Change asynchronous fragment transactions to synchronous with a call to fragment manager executePendingTransactions()
  • Сall like this
    videoOptionDialog.show(supportFragmentManager.beginTransaction().remove(videoOptionDialog),TrainingVideoMoreOptionDialog.TAG)
    

Comments

0

Better to use commitNow() for the transaction. See the docs.

/**
     * After a {@link FragmentTransaction} is committed with
     * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
     * is scheduled to be executed asynchronously on the process's main thread.
     * If you want to immediately executing any such pending operations, you
     * can call this function (only from the main thread) to do so.  Note that
     * all callbacks and other related behavior will be done from within this
     * call, so be careful about where this is called from.
     *
     * <p>If you are committing a single transaction that does not modify the
     * fragment back stack, strongly consider using
     * {@link FragmentTransaction#commitNow()} instead. This can help avoid
     * unwanted side effects when other code in your app has pending committed
     * transactions that expect different timing.</p>
     * <p>
     * This also forces the start of any postponed Transactions where
     * {@link Fragment#postponeEnterTransition()} has been called.
     *
     * @return Returns true if there were any pending transactions to be
     * executed.
     */

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.