首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在ActionBar中使用选项卡调用onCreateOptionsMenu的次数太多

在ActionBar中使用选项卡调用onCreateOptionsMenu的次数太多
EN

Stack Overflow用户
提问于 2011-08-29 06:33:39
回答 5查看 12.3K关注 0票数 15

这就是我的问题。我有一个应用程序,我正在使用带有选项卡和选项菜单的ActionBar神探夏洛克。每次我旋转模拟器时,都会为所有的片段添加菜单,即使是那些被隐藏/删除的片段(我都试过了)。

这是设置:一个FragmentActivity,它有一个ActionBar

代码语言:javascript
复制
  final ActionBar bar = getSupportActionBar();

  bar.addTab(bar.newTab()
        .setText("1")
        .setTabListener(new MyTabListener(new FragmentList1())));

  bar.addTab(bar.newTab()
        .setText("2")
        .setTabListener(new MyTabListener(new FragmentList2())));

  bar.addTab(bar.newTab()
        .setText("3")
        .setTabListener(new MyTabListener(new FragmentList3())));

  bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
  bar.setDisplayShowHomeEnabled(true);
  bar.setDisplayShowTitleEnabled(true);

这些选项卡都使用相同的监听程序:

代码语言:javascript
复制
private class MyTabListener implements ActionBar.TabListener {
  private final FragmentListBase m_fragment;


  public MyTabListener(FragmentListBase fragment) {
     m_fragment = fragment;
  }


  public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
     FragmentManager fragmentMgr = ActivityList.this.getSupportFragmentManager();
     FragmentTransaction transaction = fragmentMgr.beginTransaction();

        transaction.add(R.id.frmlyt_list, m_fragment, m_fragment.LIST_TAG);

     transaction.commit();
  }


  public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
     FragmentManager fragmentMgr = ActivityList.this.getSupportFragmentManager();
     FragmentTransaction transaction = fragmentMgr.beginTransaction();

     transaction.remove(m_fragment);
     transaction.commit();
  }


  public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
  }
}

FragmentListBase的每个子类都有自己的菜单,因此所有3个子类都有:

代码语言:javascript
复制
  setHasOptionsMenu(true);

和适当的

代码语言:javascript
复制
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
  Log.d(TAG, "OnCreateOptionsMenu");

  inflater.inflate(R.menu.il_options_menu, menu);
}

当我运行应用程序时,我可以看到onCreateOptionsMenu被多次调用,针对所有不同的片段。

我完全被难住了。

我试着发布尽可能多的代码而不是铺天盖地的,如果你发现有什么东西丢失了,请告知。

Edit I添加了更多的日志记录,结果发现片段在旋转时被附加了两次(或更多)。我注意到的一件事是,除了onCreate()方法之外,所有的东西都被多次调用,它只被调用一次。

代码语言:javascript
复制
06.704:/WindowManager(72): Setting rotation to 0, animFlags=0
06.926:/ActivityManager(72): Config changed: { scale=1.0 imsi=310/260 loc=en_US touch=3 keys=1/1/2 nav=1/2 orien=L layout=0x10000014 uiMode=0x11 seq=35}
07.374:/FragmentList1(6880): onAttach
07.524:/FragmentList1(6880): onCreateView
07.564:/FragmentList1(6880): onAttach
07.564:/FragmentListBase(6880): onCreate
07.564:/FragmentList1(6880): OnCreateOptionsMenu
07.574:/FragmentList1(6880): OnCreateOptionsMenu
07.604:/FragmentList1(6880): onCreateView

编辑2

好了,我开始追溯到Android代码,并在这里找到了这部分(我编辑了这篇文章以缩短这篇文章)。

/com_actionbarsherlock/src/android/support/v4/app/FragmentManager.java

代码语言:javascript
复制
public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    if (mActive != null) {
        for (int i=0; i<mAdded.size(); i++) {
            Fragment f = mAdded.get(i);
            if (f != null && !f.mHidden && f.mHasMenu) {
                f.onCreateOptionsMenu(menu, inflater);
            }
        }
    }

问题是mAdded中确实有多个FragmentList1实例,所以onCreateOptionsMenu()方法被“正确”调用了3次,但调用的是FragmentList1类的不同实例。我不明白的是为什么这个类会被多次添加...但这是一个地狱般的好线索。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-08-30 05:32:03

我似乎找到了问题所在。我之所以说问题,是因为在众多菜单之上,现在还有一个例外。

1)调用

代码语言:javascript
复制
  bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

这是在调用addTab()之后产生的调用onTabSelected()的副作用。然后,我的TabListener会将一个FragmentList1添加到FragmentManager

2)旋转设备将按预期销毁活动,但不会销毁碎片。在循环后创建新活动时,它将做两件事:

  1. 创建另一组将添加到FragmentManager中的片段。这就是导致大量菜单和
  2. 调用onTabSelected (通过setNavigationMode())的原因,它将执行以下代码:if (null != fragmentMgr.findFragmentByTag(m_fragment.LIST_TAG)) { transaction.attach(m_fragment);transaction.show(m_fragment);} else { transaction.add(R.id.frmlyt_list,m_fragment,m_fragment.LIST_TAG);}

基本上,如果片段已经在FragmentManager中,则不需要添加它,只需显示它即可。但这就是问题所在。这不是同一个片段!它是由活动的早期实例创建的片段。因此它将尝试附加并显示这个新创建的片段,这将导致异常

解决方案。

为了解决这一切,有几件事要做。

1)我将setNavigationMode()移到了addTab()之上。

2)这是我现在创建我的选项卡的方式:

代码语言:javascript
复制
  FragmentListBase fragment = (FragmentListBase)fragmentMgr.findFragmentByTag(FragmentList1.LIST_TAG_STATIC);
  if (null == fragment) {
     fragment = new FragmentList1();
  }
  bar.addTab(bar.newTab()
        .setText("1")
        .setTabListener(new MyTabListener(fragment)));

因此,在创建活动时,我必须检查片段是否已经在FragmentManager中。如果是,我会使用这些实例,如果不是,我会创建新的实例。对于所有三个选项卡,都会执行此操作。

您可能已经注意到有两个相似的标签: m_fragment.LIST_TAG和FragmentList1.LIST_TAG_STATIC。啊,这太可爱了.( <-讽刺)

为了多态使用我的TagListener,我在基类中声明了以下非静态变量:

代码语言:javascript
复制
public class FragmentListBase extends Fragment {
   public String LIST_TAG = null;
}

它是从子代内部分配的,允许我在FragmentManager中查找FragmentListBase的不同子代。

但我还需要在创建特定的子代之前搜索它们(因为我需要知道是否必须创建它们),因此我还必须声明以下静态变量。

代码语言:javascript
复制
public class FragmentList1 extends FragmentListBase {
   public final static String LIST_TAG_STATIC = "TAG_LIST_1";

   public FragmentList1() {
      LIST_TAG = LIST_TAG_STATIC;
   };
}

我只想说,我很失望,没有人想出这个简单而优雅的解决方案( <-更多讽刺)

非常感谢杰克·沃顿,他花时间为我看了这篇文章:)

票数 7
EN

Stack Overflow用户

发布于 2011-08-29 09:32:33

代码语言:javascript
复制
public FragmentListBase() {
    setRetainInstance(true);
    setHasOptionsMenu(true);
}

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

您可能想要进行的另一个简单更改是在选项卡选定回调中调用transaction.replace(R.id.frmlyt_list, m_fragment, m_fragment.LIST_TAG),并删除未选定回调中的内容。

票数 6
EN

Stack Overflow用户

发布于 2012-11-15 05:29:07

我在"stackable“菜单轮换的时候也遇到过类似的问题。我不使用制表符,但我使用带有FragmentStatePagerAdapter的ViewPager,所以我不能真正重用我的片段。在敲了两天头之后,我找到了非常简单的解决方案。实际上,问题似乎出在多次调用onCreateOptionsMenu上。这个小代码片段需要注意(掩码?)在所有问题中:

代码语言:javascript
复制
/** to prevent multiple calls to inflate menu */
private boolean menuIsInflated;

@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
    if (!menuIsInflated) {
        inflater.inflate(R.menu.job_details_fragment_menu, menu);
        menuIsInflated = true;
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7224415

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档