在Fragment中,onCreateOptionsMenu()被调用两次

14

我有一个简单的应用程序,带有选项菜单,并在片段开始时更改菜单。 问题是,在除第一个之外的任何片段开始时,onCreateOptionsMenu()都会被调用两次——在onCreate()中和在onResume()之后。 在onCreate()中,我通过setHasOptionsMenu(true)手动调用它,但在onResume()之后就不应该发生这种情况。 此外,这只发生在第一个片段启动之后。

以下是基础片段代码:

class BaseFragment extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle clicks
        return true;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // Create a menu
        super.onCreateOptionsMenu(menu, inflater);
    }
}

在Activity中更改片段的代码:

public void startFragment(BaseFragment fragment) {
    getSupportFragmentManager()
    .beginTransaction()
    .replace(android.R.id.content, fragment)
    .commit();
}

这个示例不使用任何外部库,如ActionBarSherlock,只使用SupportLibrary。 我猜问题在FragmentTransaction的replace()方法中,因为当第一个fragment启动时它运行得很好。但我不知道从哪里开始解决这个问题。我需要确切地在View中替换fragment。


你使用的是哪款手机?如果手机有一个专门的菜单按钮,那么只有当用户点击它时才会调用onCreateOptionsMenu。另外,不一定要调用setHasOptionsMenu(true)来添加它,它只是通知框架该片段希望在填充菜单时参与。 - prijupaul
当我遇到相同的问题时,OP甚至不允许我添加/编辑问题。我知道关于菜单的基本知识,但问题就像OP所描述的那样奇怪。 编辑:我正在使用嵌套片段。 - Zyoo
@Zyoo 我写的代码完全重现了这个错误。我认为我在某个地方犯了错误,于是创建了一个最小化的项目。我没有找到解决办法,只能修改代码使其独立于这种行为。 - bvitaliyg
好的,也许我们有不同的问题,或者是相同的问题,我会再提供一些测试用例。 - Zyoo
@bvitaliyg:我用ICS(Nexus手机)和JB版本(Nexus 7平板电脑)做了一个示例应用程序。虽然我在onCreate中设置了setHasOptionsMenu,但只有当我按下菜单按钮时才会调用onCreateOptionsMenu。 - prijupaul
显示剩余2条评论
5个回答

8
最简单的解决方法是在菜单被填充之前清除菜单。menu.clear()将清除任何现有的菜单,并开始一个新的菜单。
@Override
 public void   onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
      super.onCreateOptionsMenu(menu, inflater);
      menu.clear();
      inflater.inflate(R.menu.sample_menu, menu);
 }

7

我知道我来晚了,但也遇到了同样的问题-我的解决方案实际上是明确添加

setHasOptionsMenu(false);

在我的SupportFragments的onCreate函数中加入这段代码。这将防止任何额外的调用到活动的 onCreateOptionsMenu和onPrepareOptionsMenu 函数。希望这可以帮助你。


3
我猜新添加的片段导致了活动的onCreateOptionsMenu被再次调用!

1>尝试在片段构造函数中添加

setRetainInstance(true);

 public BaseFragment()
 {
    setRetainInstance(true);
    setHasOptionsMenu(true);
 }

这将在旋转时保存/恢复每个片段的各自状态。
问题似乎与Android在活动被销毁时(设备旋转时)不销毁片段有关。
我在这里找到了Jake Wharton在SO上的解决方法
更新: 另一种方式是避免在布局文件中添加片段,也通过调用构造函数/newInstance方法手动实例化它们。
如果您在布局中添加片段,则Android框架将为您实例化它。 而不是手动实例化片段,您应该通过调用FragmentManager.getFragmentById来检索其实例,并使用该实例代替它。
因此,始终为您的片段包括ID和/或标记。
尝试调用menu.clear()。
  @Override
     public void   onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
          menu.clear();
          inflater.inflate(R.menu.call_menu, menu);
          super.onCreateOptionsMenu(menu, inflater);

     }

2
不,我不认为这是答案。当然,我尝试了你上面说的所有方法,但每次测试时仍然会出现这种情况。 - Zyoo
@Zyoo,你有没有其他的解决方案? - LOG_TAG
抱歉,我决定不使用OptionMenu,但我认为将来可能会需要,所以我仍在尝试。 - Zyoo

0

你可以尝试这样做:

    private final int MENU_SEARCH=Menu.FIRST;
:
    @Override public void onPrepareOptionsMenu(Menu menu) {
        if (menu.findItem(MENU_SEARCH)==null) {
            menu.add(0, MENU_SEARCH, Menu.NONE, getText(R.string.menu_search));
:

即检查菜单项是否存在于菜单中,如果不存在,则可能需要添加所有菜单项。


0

使用menu?.clear()是一个解决办法。在使用之前,请确保您没有从MainActivity重新创建片段。由于配置更改,应用程序长时间处于后台等原因,活动和片段将被自动重新创建。因此,在MainActivity中我们不需要再次创建MyFragment

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  if (savedInstanceState == null) { // This is what prevents recreating the fragment
    supportFragmentManager
      .beginTransaction()
      .add(R.id.fragment_container, MyFragment())
      .commit()
  }
}

如果您不进行检查,片段将在活动重新创建时再次添加。因此,工具栏将具有重复的菜单选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接