6

I am trying to remove a fragment but very rarely on Crashlytics I am able to see a bug java.lang.IllegalStateException: Cannot remove Fragment attached to a different FragmentManager.

I have a separate fragment for fetching user's current location. I use below code to open the fragment.

private void openLocationFragment() {
    LocationFragment locationFragment = LocationFragment.newInstance();
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.beginTransaction()
            .replace(R.id.fragmentContainer, locationFragment, "location_fragment")
            .commitAllowingStateLoss();
}

Now In fragment as soon as i get a location update, I call method onLocationFetched using listener attached to the activity.

Inside this method I remove the fragment using below code.

@Override
public void onLocationFetched(Location location) {
    FragmentManager fragmentManager = getSupportFragmentManager();
    LocationFragment locationFragment = (LocationFragment) fragmentManager.findFragmentByTag("location_fragment");
    if (locationFragment != null) {
        fragmentManager.beginTransaction()
                .remove(locationFragment) // Here is the exception
                .commitAllowingStateLoss();
    }
    if(location == null){
        fetchUserDetails();
    }else
        fetchCity(location);
}

StackTrace:

Fatal Exception: **java.lang.IllegalStateException: Cannot remove Fragment attached to a different FragmentManager.** 

Fragment LocationFragment{32a2ed0 (d41fc341-baf2-4266-948a-866fba7e57b5) id=0x7f09028b location_fragment} is already attached to a FragmentManager.
       at androidx.fragment.app.BackStackRecord.remove(BackStackRecord.java:316)
       at com.avail.easyloans.feature.marketplace.activities.ActivityMarketplace.onFragmentFetched(ActivityMarketplace.java:909)
       at com.avail.easyloans.base.fragments.LocationFragment.sendLocationToClient(LocationFragment.java:192)
       at com.avail.easyloans.base.fragments.LocationFragment.access$000(LocationFragment.java:46)
       at com.avail.easyloans.base.fragments.LocationFragment$4.onSuccess(LocationFragment.java:220)
       at com.avail.easyloans.base.fragments.LocationFragment$4.onSuccess(LocationFragment.java:214)
       at com.google.android.gms.tasks.zzn.run(zzn.java:4)
       at android.os.Handler.handleCallback(Handler.java:836)
       at android.os.Handler.dispatchMessage(Handler.java:103)
       at android.os.Looper.loop(Looper.java:203)
       at android.app.ActivityThread.main(ActivityThread.java:6339)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1084)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:945)

What's wrong am I doing here?

AskNilesh
  • 67,701
  • 16
  • 123
  • 163
Prashant Jha
  • 574
  • 6
  • 21
  • Are you calling `getSupportFragmentManager()` from different Activities? – PPartisan Apr 05 '19 at 10:13
  • yes, but this fragment is not used in any other activity. – Prashant Jha Apr 05 '19 at 10:14
  • That would explain your error then - each Activity will have its own `FragmentManager` for managing its own fragments – PPartisan Apr 05 '19 at 10:15
  • @PPartisan If this fragment is not used in any other activity, will it still impact `FragmentManager` – Prashant Jha Apr 05 '19 at 10:19
  • You can check against the resource id value of the container instead of by tag value with `findFragmentById()`. Alternatively, you can launch your other Activity that contains your Location Fragment – PPartisan Apr 05 '19 at 10:24
  • @PPartisan Can you reference this with some code? I am unable to get what you trying to convey. – Prashant Jha Apr 05 '19 at 10:32
  • Possible duplicate of [android expandablelistview does not expand or receive click events](https://stackoverflow.com/questions/11008286/android-expandablelistview-does-not-expand-or-receive-click-events) – Swati Garg Jul 17 '19 at 15:35

1 Answers1

5

I expect that each Activity is responsible for maintaining its own Fragments. This would means that if the Fragment you are trying to access is associated with another Activity's FragmentManager, then your app will fail.

I can think of a couple of ways around this, depending on the behaviour you want. If you don't mind having two LocationFragments having their own separate lifecycles in two separate activities, you can access them with findFragmentById() on your FragmentManager. I.e.:

private void openLocationFragment() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    final Fragment current = fragmentManager.findFragmentById(R.id.fragmentContainer);
    if(current == null || !(current instanceof LocationFragment)) {
        fragmentManager.beginTransaction()
            .replace(R.id.fragmentContainer, LocationFragment.newInstance())
            .commitAllowingStateLoss();
    }
}

And do the same in your other Activity. Alternatively, you can invoke your other Activity that hosts the LocationFragment in onLocationFetched()

PPartisan
  • 8,173
  • 4
  • 29
  • 48