gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 19:06:06 26 4
gpt4 key购买 nike

这是我的问题。我有一个应用程序,我在其中使用带有选项卡的 ActionBar Sherlock,带有选项菜单的 fragment 。每次我旋转模拟器时,都会为所有 fragment 添加菜单,即使是隐藏/删除的 fragment (我都试过了)。

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

的 ActionBar
  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);

所有选项卡都使用相同的监听器:

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 个子类都有:

  setHasOptionsMenu(true);

和适当的

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Log.d(TAG, "OnCreateOptionsMenu");

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

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

我完全被难住了。

我尽量贴出尽可能多的代码而不至于让人不知所措,如果您发现有什么地方遗漏了,请指教。

[编辑]我添加了更多日志记录,结果发现该 fragment 在旋转时被附加了两次(或更多)。我注意到的一件事是,除仅调用一次的 onCreate() 方法外,所有内容都被多次调用。

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

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 类的不同实例。我不明白的是为什么要多次添加该类...但这是一个很好的线索。

最佳答案

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

1) 调用

  bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

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

2) 旋转设备会按预期销毁 Activity,但不会销毁 Fragment。当旋转后创建新 Activity 时,它会做两件事:

  1. 创建另一组将添加到 FragmentManager 的 Fragment。这就是造成大量菜单的原因
  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);
    }

基本上,如果 fragment 已经在 FragmentManager 中,则无需添加,只需显示即可。但问题就在这里。这不是同一个 fragment !它是由 Activity 的早期实例创建的 Fragment。所以它会尝试附加并显示这个新创建的 fragment ,这会导致异常

解决方案。

要解决所有这些问题,需要做一些事情。

1) 我将 setNavigationMode() 移到 addTab() 上方。

2) 这就是我现在创建标签的方式:

  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)));

因此,在创建 Activity 时,我必须检查 Fragment 是否已经在 FragmentManager 中。如果是,我使用这些实例,如果不是,那么我创建新的实例。这对所有三个选项卡都完成了。

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

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

public class FragmentListBase extends Fragment {
public String LIST_TAG = null;
}

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

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

public class FragmentList1 extends FragmentListBase {
public final static String LIST_TAG_STATIC = "TAG_LIST_1";

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

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

非常感谢 Jake Wharton 花时间帮我看这个:)

关于android - 使用选项卡在 ActionBar 中调用 onCreateOptionsMenu 的次数太多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7224415/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com