问题 onCreateOptionsMenu()在Fragment中调用两次


我有一个带有选项菜单的简单应用程序,它在片段的开头变化。 问题是,在开始时,除了第一个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()方法中,因为它在第一个片段启动时工作正常。但我不知道,从哪里开始解决问题。我需要在View中完全替换片段。


11549
2018-05-12 09:40


起源

你用的是哪款手机?如果手机有专门的菜单按钮,则只有在用户点击它时才会调用onCreateOptionsMenu。要添加,setHasOptionsMenu(true)不应强制调用onCreateOptionsMenu。它只是在填充菜单时通知框架片段想要参与。 - prijupaul
当我遇到同样的问题时,OP甚至不允许我添加/编辑问题。我知道关于Menu的基本内容,问题很像OP描述的那样。编辑:我正在使用嵌套片段 - Zyoo
@prijupaul它实际上只适用于蜂窝前版本。在Honeycomb和稍后onCreateOptionsMenu将在调用setHasOptionsMenu()后立即调用。 - bvitaliyg
@Zyoo我写的代码完全重现了这个bug。我以为我在某个地方犯了一个错误,所以用最少的代码创建了一个新项目。我还没有找到解决方案,不得不改变代码,使其独立于这种行为。 - bvitaliyg
好吧,不管我们有不同的问题或相同,我会再给一些测试用例 - Zyoo


答案:


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

setHasOptionsMenu(false);

到我的SupportFragments onCreate函数。这可以防止对活动'onCreateOptionsMenu和onPrepareOptionsMenu的任何额外调用。希望这可以帮助。


7
2018-06-13 13:45





解决问题的最简单方法是在菜单膨胀之前清除菜单。

menu.clear()将清除任何现有菜单,并开始使用新菜单。

@Override
 public void   onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
      super.onCreateOptionsMenu(menu, inflater);
      menu.clear();
      inflater.inflate(R.menu.sample_menu, menu);
 }

3
2018-01-15 14:47





我想新添加的片段会导致再次调用onCreateOptionsMenu上的活动!

1>尝试添加

setRetainInstance(真);

片段构造函数!

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

这将在旋转时保存/恢复每个片段的各个状态

这个问题似乎与Android在活动被销毁时(旋转设备时)不破坏碎片的事实有关。

我在这里找到了这个 杰克沃顿 在SO

更新: 2>另一种方法是避免在布局文件中添加片段,并通过调用构造函数/ newInstance方法手动实例化它们。

如果在布局上添加片段,android框架将为您实例化它。 您应该通过调用FragmentManager.getFragmentById并使用该实例来检索它的实例,而不是手动实例化片段。

因此,请始终为您的片段添加ID和/或标记

3>通过调用menu.clear()试试这个

  @Override
     public void   onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
          menu.clear();
          inflater.inflate(R.menu.call_menu, menu);
          super.onCreateOptionsMenu(menu, inflater);

     }

2
2017-09-25 07:18



不,我不认为这是答案。当然我尝试了你上面所说的所有但是每当我测试它时它仍然会发生 - Zyoo
@Zyoo为您的问题找到了其他解决方案? - LOG_TAG
抱歉,不,我决定不使用optionmenu,但我认为将来它会被需要,所以我还在尝试 - Zyoo


你也许可以这样试试:

    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
2018-01-14 22:10





如果不处理菜单项,则应调用onOptionsItemSelected()的超类实现(默认实现返回false)。

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    return super.onOptionsItemSelected(item);
}

-1
2017-09-25 05:34



为什么要投票?什么是错的。 - Ahsan Shah
我认为它的问题与onCreateOptionsMenu有关,你的答案是与onResume有关,这与onCreateOptionMenu和生命周期不合适。 - prijupaul
不。它不是手动调用的。当调用setHasOptionsMenu(true)时,它只是通知框架片段有菜单。框架在适当时调用所需的函数。如果未设置为true,则框架不会在片段中调用oncreateoptionsmenu。 - prijupaul