【问题标题】:Got exception: fragment already active出现异常:片段已激活
【发布时间】:2012-05-09 00:27:26
【问题描述】:

我有一个片段

MyFragment myFrag = new MyFragment();

我把捆绑数据放到这个片段中:

Bundle bundle = new Bundle(); 
bundle.putString("TEST", "test");
myFrag.setArguments(bundle);

然后,我用这个替换旧片段并放入backstack

//replace old fragment
fragmentTransaction.replace(R.id.fragment_placeholder, myFrag, "MyTag");
//put on backstack
fragmentTransaction.addToBackStack(null);
//commit & get transaction ID
int transId = fragmentTransaction.commit();

后来,我用上面的事务ID(transId)pop backstack

//pop the transaction from backstack
fragmentManager.popBackStack(transId,FragmentManager.POP_BACK_STACK_INCLUSIVE); 

稍后,我将 捆绑数据 再次设置为我的片段(myFrag)的参数:

//Got Java.lang.IllegalStateException: fragment already active
myFrag.setArguments(bundle);

如您所见,我上面的代码出现异常 Java.lang.IllegalStateException: fragment already active我不明白为什么 myFrag 仍然处于活动状态,尽管我已经从后台弹出了它的事务。,无论如何,因为我得到了异常,所以我认为我没有选择但停用片段,所以,我做到了:

Fragment activeFragment = fragMgr.findFragmentByTag("MyTag");
fragmentTransaction.remove(activeFragment);

我不确定我上面的代码是否真的可以停用片段,因为我没有找到如何停用片段。 :(

之后,当我再次尝试将捆绑数据设置到我的片段myFrag 时,我仍然遇到同样的错误:

Java.lang.IllegalStateException: fragment already active

似乎即使我删除了片段,它仍然处于活动状态......为什么?如何停用片段?

【问题讨论】:

标签: android android-layout android-intent android-emulator android-fragments


【解决方案1】:

阅读setArguments(Bundle args) 源代码将帮助您理解:

/**
* Supply the construction arguments for this fragment.  This can only
* be called before the fragment has been attached to its activity; that
* is, you should call it immediately after constructing the fragment.  The
* arguments supplied here will be retained across fragment destroy and
* creation.
*/
public void setArguments(Bundle args) {

    if (mIndex >= 0) {
        throw new IllegalStateException("Fragment already active");
    }
    mArguments = args;
}

您不能在同一Fragment 的代码中再次使用setArguments(Bundle args)。我猜你想要做的是创建一个 new Fragment 并再次设置参数。或者你可以使用getArguments(),然后使用bundle的put方法来改变它的值。

【讨论】:

  • +1 表示“你可以使用 getArguments() 然后使用 bundle 的 put 方法来改变它的值。”
  • 这是一个很好的例子,也有详细的解释。 emuneee.com/blog/2013/01/07/saving-fragment-states
  • getArguments().putAll(bundle); 将覆盖整个包
  • getArguments().putAll(bundle); 不会覆盖整个捆绑包。调用此键后,我仍然拥有以前的键和值。就我而言,我使用了 getArguments().clear(); 并清理了参数。
  • 如果之前没有设置 setArguments(),则不能使用 getArguments().putAll(),因为 getArguments() 返回 null。
【解决方案2】:

在添加新片段之前尝试删除之前的片段:https://stackoverflow.com/a/6266144/969325

【讨论】:

  • 我首先尝试了 "fragmentTransaction.remove(myFrag)" 然后 "replace(...)" ,它没有帮助。我有同样的例外
  • nono 以前的。所以堆栈上的任何东西都用 remove 删除,然后用 myfrag 替换。
  • fragmentTransaction.remove(myFrag) 从其addedFragment 堆栈中删除片段,但将其实例保留在其activeFragment 堆栈中。
【解决方案3】:

remove() 将片段状态更改为停用。在您的情况下,您只是没有在 remove(..) 之后调用 commit()。

fragmentTransaction.remove(activeFragment);

你也可以在 remove() 之后执行 commit()。

fragmentTransaction.remove(activeFragment).commit();

【讨论】:

    【解决方案4】:

    有同样的问题。我正在将片段添加到后台堆栈。错误是因为我没有调用 popbackstack()。使用 popbackstack 帮助了我

    【讨论】:

      【解决方案5】:

      我在 Xamarin.android 上遇到了同样的问题。 the documentation 是这么说的。

      这只能在片段附加到其活动之前调用

      【讨论】:

        【解决方案6】:

        只需从片段中调用公共方法

        if(userFragment==null){
                            userFragment = new UserFragment();
                            Bundle bundle = new Bundle();
                            bundle.putString(Constants.EXTRA_CUSTOMER, result);
                            userFragment.setArguments(bundle);
                        }else{
                            try {
                                Customer customer = new Customer();
                                customer.parseCustomer(new JSONObject(result));
                                userFragment.updateVeiw(customer);
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
        

        【讨论】:

          【解决方案7】:

          首先我会描述为什么会发生这种情况,然后我会想出我发现可行的解决方案......

          当 Android 从堆栈中移除片段但尚未完成移除时,会发生此问题。为了检查这一点,您可以使用片段的isRemoving() 方法。如果false,即片段未激活,您可以继续使用setArguments(bundle) 设置参数。否则,您无法为已经处于活动状态的片段设置参数,只能通过使用getArguments().putAll(bundle) 寻址相同的参数来覆盖它。

          总结一下,

              if (myFrag.isRemoving()) {
                  myFrag.getArguments().putAll(bundle);
              } else {
                  myFrag.setArguments(bundle);
              }
          

          如果您想避免这种情况,即立即删除片段以便没有活动片段,您可能希望在onBackStackChangedListener() 中使用onBackPressed(),这会将isRemoving() 设置为false

          【讨论】:

            【解决方案8】:
            1. 例如检查您的布局是当前的还是旧的

              setContentView(R.layout.activity_main);
              
            2. 删除项目文件中的旧 .gradle 文件并为项目重建 gradle 文件。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-11-28
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-01-16
              • 2020-06-19
              • 2013-10-18
              相关资源
              最近更新 更多