【问题标题】:Fragment already added IllegalStateException片段已添加 IllegalStateException
【发布时间】:2011-09-09 04:26:06
【问题描述】:

我在我的容器 Activity 上使用此方法来显示 BFrag

public void showBFrag()
{
    // Start a new FragmentTransaction
    FragmentTransaction fragmentTransaction = mFragmentMgr.beginTransaction();

    if(mBFrag.isAdded())
    {
        Log.d(LOG_TAG, "Show() BFrag");
        fragmentTransaction.show(mBFrag);   
    }
    else
    {
        Log.d(LOG_TAG, "Replacing AFrag -> BFrag");
        fragmentTransaction.replace(R.id.operation_fragments_frame, mBFrag);
    }

    // Keep the transaction in the back stack so it will be reversed when backbutton is pressed
    fragmentTransaction.addToBackStack(null);

    // Commit transaction
    fragmentTransaction.commit();        
}

我从我的容器 Activity 中调用它;第一次:

  • 进入 else 语句,mBFrag 替换 mAFrag。

然后我按下返回键:

  • 操作相反(显示了 mAFrag,但.. mBFrag 是否被删除?)。

然后我通过从同一个 Activity 调用 showBFrag() 再次前进:

  • 然后它再次进入 else 语句。 (所以我可以推断未添加 mBFrag)
  • 但是我得到了一个Fragment already added IllegalStateException...(那为什么它没有进入 if 语句呢?)

所以:

  1. 如果我得到 Fragment already added IllegalStateException,为什么 isAdded() 方法不返回 TRUE?
  2. popBackStack 操作是否会完全删除之前添加的片段?
  3. 我误解了什么行为?

编辑: 这是异常的完整信息。

06-07 12:08:32.730: ERROR/AndroidRuntime(8576): java.lang.IllegalStateException: Fragment already added: BFrag{40b28158 id=0x7f0c0085}
06-07 12:08:32.730: ERROR/AndroidRuntime(8576):     at android.app.BackStackRecord.doAddOp(BackStackRecord.java:322)
06-07 12:08:32.730: ERROR/AndroidRuntime(8576):     at android.app.BackStackRecord.replace(BackStackRecord.java:360)
06-07 12:08:32.730: ERROR/AndroidRuntime(8576):     at android.app.BackStackRecord.replace(BackStackRecord.java:352)
06-07 12:08:32.730: ERROR/AndroidRuntime(8576):     at myPackageName.containerActivity.showBFrag() // This line: "fragmentTransaction.replace(R.id.operation_fragments_frame, mBFrag);"

【问题讨论】:

标签: android android-3.0-honeycomb android-fragments fragment illegalstateexception


【解决方案1】:

最后我的解决方法是执行前一个片段的 remove() 并 add() 新片段。虽然这就是 replace() method 的本意。

但我仍然在猜测为什么 replace() 方法在这种情况下不能正常工作。这真的很奇怪,我想放弃这是因为我误解了某事或做错了什么。

【讨论】:

  • @AMGG 我很想知道您是否使用兼容性库和非兼容版本进行了测试,发现这两者都有问题,因为我使用replace(...) 和前者没有问题(我的第一个片段添加了add(...)
  • @AMGG,@schwiz,这也是 CPL 中的一个错误。问题出在BackStackRecord:popFromBackStack 中,在“OP_REPLACE”上,活动被分配给已删除的片段中的变量,而不是正在重新添加的片段中的变量。除非其他人愿意这样做,否则我会提出错误报告。是否有人需要澄清他们的答案,因为这是一个错误的解决方法,而不是挂在参考上的问题?干杯,伙计们。
  • @AMGG,@schwiz bug report link。问题 17488。
  • 有没有人找到更好的解决这个问题的方法,或者现在使用 remove() 然后 add() 是唯一可行的解​​决方案?
  • 你说删除前一个片段,但是你如何找到这个片段?使用 FragmentManager ?
【解决方案2】:

如果活动的状态已经被保存,那么调用提交就不再安全了。您必须改为致电 commitAllowingStateLoss()。希望这会有所帮助!

编辑:好的,我仔细研究了您的问题,问题是您正在尝试添加已添加的片段。即使您使用替换或删除呼叫,您也不能这样做。我发现的唯一解决方法是创建一个片段的新实例并每次都添加它。删除或替换片段后,最好删除对它的所有引用,以便 GC 处理它。

【讨论】:

  • 没有任何迹象表明执行提交是不安全的,根据经验,如果是这种情况,无论如何您都会抛出不同的异常。据我所见,用户只是通过按下后退按钮返回,然后在某处进行选择以再次加载片段,类似于 AndroidDevelopers 的 FragmentStack API 演示示例。我会与那个例子进行比较,看看区别在哪里。
  • @PJL 我的经验是在这种情况下会抛出 IllegalStateException。
  • 抱歉,是相同的异常,但表示不同的消息,例如 “在 onSaveInstanceState 之后无法执行此操作”。再次没有任何迹象表明调用commit是不保存的。
  • commitAllowingStateLoss() 没有解决它。但很高兴知道它。谢谢
  • @AMGG 好的,很抱歉造成混乱,请参阅我的更新答案,我也遇到过这个问题。不确定这是兼容性库的问题还是一般的片段问题。
【解决方案3】:

可能与此问题没有直接关系,但我也注意到设置到 FragmentTransaction 的转换会导致 IllegalStateException,而不设置转换则不会。

这里是这个问题的错误:http://code.google.com/p/android/issues/detail?id=25598

【讨论】:

    【解决方案4】:

    我用过这个:

    if (getFragmentManager().findFragmentByTag(newFragment.getClass().getName()) != null) {
       transaction.remove(newFragment);
     }
    

    并添加了片段

    MyFragment frag = new MyFragment(); 
    transaction.add(R.id.container, frag, MyFragment.class.getName())
    

    MyFragment.class.getName() 代表tag

    【讨论】:

      【解决方案5】:

      使用方法fragment.isAdded()检查frament是否已经添加,做相应的替换或添加片段

      【讨论】:

        【解决方案6】:

        在 fragmentTransection.replace() 之后试试这个

        fragmentTransection.addToBackStack(null);
        fragmentTransection.commitAllowingStateLoss();
        

        【讨论】:

          【解决方案7】:

          Viewpager 中删除setOffscreenPageLimit 解决了我的问题。 谢谢。

          【讨论】:

            【解决方案8】:

            我尝试从onTabUnselected() 调用FragmentTransaction.remove(),它解决了这个错误。

            @Override
            public void onTabSelected(Tab tab, FragmentTransaction ft) {
                ft.add(R.id.fragment_container, fragment, null);
            }
            
            @Override
            public void onTabUnselected(Tab tab, FragmentTransaction ft) {
                ft.remove(fragment);
            }
            

            【讨论】:

              【解决方案9】:

              这段代码对我来说很好用。试试这个

              ((MiActivity)getActivity()).addAccount = new AddAccount();
              ((MiActivity)getActivity()).addAccount.setArguments(params);
              fragmentManager = getActivity().getSupportFragmentManager();
              fragmentTransaction = fragmentManager.beginTransaction();
              fragmentTransaction.replace(R.id.fragment_container((MiActivity)getActivity()).addAccount);
              fragmentTransaction.addToBackStack(null);
              fragmentTransaction.commit();
              

              【讨论】:

                【解决方案10】:

                通过遍历我的片段并检查 isAdded() 是否为真,然后删除该片段来解决它。 More details here.

                【讨论】:

                  【解决方案11】:

                  使用列表保存片段实例,并判断:

                          if (!mFragmentTags.contains(fragTag + "")) {
                                  transaction.add(R.id.tab_main_container, mCurrentFragment, fragTag + "");
                  }
                  
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多