onCreateOptionsMenu()在Fragment中调用两次

时间:2013-05-12 09:40:54

标签: android-fragments android-optionsmenu

我有一个带有选项菜单的简单应用程序,它在片段的开头变化。 问题是,在开始时除了第一个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中完全替换片段。

6 个答案:

答案 0 :(得分:7)

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

setHasOptionsMenu(false);

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

答案 1 :(得分:3)

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

menu.clear()将清除所有现有菜单,并从新菜单开始。

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

答案 2 :(得分:2)

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

1>尝试添加

  

setRetainInstance(真);

到片段构造函数!

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

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

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

我在SO

中找到了Jake Wharton

更新: 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);

     }

答案 3 :(得分: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));
:

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

答案 4 :(得分:0)

使用import React, { useEffect } from 'react'; import styled from 'styled-components'; import FoodListItem from '../molecules/FoodListItem'; const rawFoodList = ({className}) => { const [foodList, setFoodList] = useState([]); useEffect(() => { async function fetchFoodList() { const res = await fetch('api-url'); res.json() .then(res => setFoodList(res)) .catch(err => console.log(err)); console.log(foodList); } fetchFoodList(); }) return ( <ul className={className}> {foodList.map((food, index) => <FoodListItem key={index} food={food} />)} </ul> ); } const FoodList = styled(rawFoodList)` width: 100%; margin: 0; padding: 0; `; export default FoodList; 是一种解决方法。在使用它之前,请确保您没有从menu?.clear()重新创建片段。在由于配置更改而重新创建应用程序时,应用程序长时间处于后台,等等,活动和片段会自动重新创建。因此,我们不再需要MainActivity来创建MainActivity

MyFragment

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

答案 5 :(得分:-1)

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

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