简体   繁体   English

从 Backstack 添加 Fragment 时出现 IllegalStateException

[英]IllegalStateException when adding Fragment from Backstack

From time to time I get the following crash report:我不时收到以下崩溃报告:

java.lang.IllegalStateException: 
  at androidx.fragment.app.FragmentManagerImpl.addFragment (FragmentManagerImpl.java:1916)
  at androidx.fragment.app.BackStackRecord.executePopOps (BackStackRecord.java:828)
  at androidx.fragment.app.FragmentManagerImpl.executeOps (FragmentManagerImpl.java:2622)
  at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether (FragmentManagerImpl.java:2411)
  at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute (FragmentManagerImpl.java:2366)
  at androidx.fragment.app.FragmentManagerImpl.execPendingActions (FragmentManagerImpl.java:2273)
  at androidx.fragment.app.FragmentManagerImpl$1.run (FragmentManagerImpl.java:733)
  at android.os.Handler.handleCallback (Handler.java:808)
  at android.os.Handler.dispatchMessage (Handler.java:101)
  at android.os.Looper.loop (Looper.java:166)
  at android.app.ActivityThread.main (ActivityThread.java:7529)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:245)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:921)

In line 1916 of FragmentManagerImpl I can find:在 FragmentManagerImpl 的第 1916 行中,我可以找到:

throw new IllegalStateException("Fragment already added: " + fragment);

So it says that some fragment is already added.所以它说已经添加了一些片段。 Unfortunately Google does not show the message (which fragment was already added) in the Google Play Console anymore.不幸的是,Google 不再在 Google Play 控制台中显示该消息(已添加哪个片段)。 As far as I understand the Stacktrace this exception occurs when adding a fragment from the backstack right?据我了解 Stacktrace 在从 backstack 添加片段时会发生此异常,对吗?

I have one FrameLayout in which I add/remove Fragments.我有一个FrameLayout ,我可以在其中添加/删除 Fragments。 I always add them with following code:我总是使用以下代码添加它们:

public void addFragment(FragmentActivity activity, Fragment fragment) {
    FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
    String tag = fragment.getClass().getCanonicalName();
    Fragment prev = activity.getSupportFragmentManager().findFragmentByTag(tag);
    if (fragment.isAdded()) {
        return;
    }
    if (prev != null) {
        transaction.remove(prev);
    }
    transaction.replace(R.id.fragment_container, fragment, tag);
    transaction.addToBackStack(null);
    transaction.commit();

And I add DialogFragments with following method:我使用以下方法添加 DialogFragments :

public void openFragmentDialog(FragmentActivity activity, DialogFragment dialogFragment, String tag) {
    FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
    Fragment prev = activity.getSupportFragmentManager().findFragmentByTag(tag);
    if (prev != null) {
        transaction.remove(prev);
    }
    transaction.addToBackStack(null);
    dialogFragment.show(transaction, tag);
}

In which situation could it happen that the IllegalStateException occurs?在什么情况下会发生 IllegalStateException? Am I adding/replacing the Fragments/DialogFragments the wrong way?我是否以错误的方式添加/替换 Fragments/DialogFragments? I could never reproduce that error.我永远无法重现那个错误。 But I get reports from Android 4.4 - Android 9 and all types of devices and I have no idea where it could happen.但是我从 Android 4.4 - Android 9 和所有类型的设备收到报告,我不知道它可能发生在哪里。

Could it be something with animations or slow devices?它可能是带有动画或慢速设备的东西吗? Because it only happens occasionally.因为它只是偶尔发生。

tag need to be unique. tag必须是唯一的。 If possible replace it with null , otherwise with something unique.如果可能,用null替换它,否则用独特的东西替换它。

public void addFragment(FragmentActivity activity, Fragment fragment) {
    FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment_container, fragment);
    transaction.addToBackStack(null);
    transaction.commit();
}

Note, you are adding and removing two different fragments with the same tag -- the tag should then also be different.请注意,您正在添加和删除具有相同标签的两个不同片段——标签也应该不同。 If the prev fragment is an instance of a different class, why are you using fragment 's class name as the tag to find it?如果prev片段是一个不同的类的实例,你为什么使用fragment的类名作为标签来找到它?

You should add an if statement to check if prev and fragment are not sometimes the same instance (because of same tag).您应该添加一个if语句来检查prevfragment有时是否不是同一个实例(因为相同的标签)。

If the two fragments are the same instance and you still want to remove and then add the same fragment -- you might have to do it in two different transactions to prevent "Fragment already added" exception.如果这两个片段是同一个实例,并且您仍然想要删除然后添加相同的片段——您可能必须在两个不同的事务中执行此操作以防止"Fragment already added"异常。

Here's what I've done to check for and prevent duplicate fragments:这是我为检查和防止重复片段所做的工作:

MyFragment myFragment = (MyFragment) fragmentManager.findFragmentByTag(MY_FRAGMENT_TAG);

if(myFragment != null && myFragment.isVisible()){
    // Return early if the fragment already exists & is visible
    return;

}else if(myFragment == null){
    // Create a new instance of the fragment if none already exist
    myFragment = new MyFragment();
}

// Perform the fragment transaction
fragmentManager.beginTransaction()
    .replace(R.id.content_container, myFragment, MY_FRAGMENT_TAG)
    .addToBackStack(MY_FRAGMENT_TAG) // Pass in the tag if you want to add to the back stack
    .commit();

For Dialog Fragments I just create a new instance and call .show() on it.对于对话框片段,我只是创建一个新实例并在其上调用.show() The dialog should be dismissed through interaction with it:应该通过与其交互来关闭对话框:

MyDialog myDialog = new MyDialog();

// I call getChildFragmentManager here b/c I was using this from within a fragment
// but you can get whichever Fragment Manager is appropriate
myDialog.show(getChildFragmentManager(), MY_DIALOG_TAG);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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