1

我有一个活动,A,和两个片段,B和C.片段选项菜单 - 在片段堆栈

在这两种片段B和C创建多个实例,我请在onCreate()方法setHasOptionsMenu(true)

此外,对于每个我使用下列方法:

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

    getActivity().invalidateOptionsMenu(); // Doesn't help much... 
    menu.clear(); 
    inflater.inflate(R.menu.menu_act_detail, menu); 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    if (item.getItemId() == R.id.action_favorite_act) { 
     Log.d(TAG, title); 
     return true; 
    } else if (item.getItemId() == R.id.action_visit_site_act) { 
     Intent i = new Intent(Intent.ACTION_VIEW); 
     i.setData(Uri.parse(url)); 
     startActivity(i); 
     return true; 
    } 
    return super.onOptionsItemSelected(item); 
} 

所以片段的每个实例B和C具有标题和URL。但是,当我向片段堆栈添加多个不同的B和C实例时,当我触发action_favorite_act选项菜单项时,它会记录第一个实例的标题。

这是我使用到B或C的一个实例添加到所述片段栈的代码:

FragmentManager fragmentManager = getSupportFragmentManager(); 
Fragment fragment = ActDetailFragment.newInstance(id); 
fragmentManager.beginTransaction() 
      .add(R.id.flContent, fragment, id) 
      .addToBackStack(null) 
      .commit(); 

在这种情况下,id是相同属于每个实例的url域。

实施例的行为:

  • 我添加B的一个实例与标题的片段堆栈= “你好” 和url = “test.com”

  • 我触发action_favorite_act菜单项和它记录hello

  • 我加一个C的实例与标题=“世界”的片段堆栈和URL =“site.com”

  • 我触发action_favorite_act菜单项,并将其记录world

  • 我添加B的另一个实例与标题=“再见”的片段堆和url =“another.com”

  • 我触发action_favorite_act菜单项,它记录hello而不是goodbye

无论我添加了多少个B或C实例,菜单项似乎都会追溯到第一个实例。因此,helloworld会获得日志记录,而不是位于堆栈顶部的B和C实例的标题。我如何获得堆栈顶部的菜单项以响应操作?

+1

由于您使用的是'addToBackStack()',您是否可以确认在添加完例如B,C,B,C,B,C,B,C你可以按下后退按钮并查看同一片段的多个实例?我很好奇,如果add()实际上并没有添加片段,因为已经添加了具有该ID的另一个片段。 –

+0

@ BenP。是的,当我按下后退按钮时,我会返回到添加到后端堆栈的每个片段。 – wayway

+1

当你不调用menu.clear()时会发生什么,它是否显示每个Fragment副本的菜单? – lionscribe

回答

1

我写了一个小应用程序来尝试复制您的问题,我可以。通过一种好运,我用一个透明背景为我的片段,这是有益的,因为这意味着我看到我所有的片段是活一次:

enter image description here

和你一样,我注意到,当我选择选项菜单项时,我总是记录相同的消息(来自第一个片段)。

问题的根源似乎是您的片段类的每个实例对其菜单项使用相同的R.id常量。所以你有在您的活动中有三个Fragment B实例,但全部三个都可以处理R.id.action_favorite_act的点击。据推测,该活动只是遍历其片段,并将菜单事件传递给每个人直到有人处理它,因此第一个总是获胜。

您可以通过使用replace()而不是add()来解决此问题,以便任何时候只有一个给定片段类的实例处于活动状态并附加。

如果这不符合您的要求,我相信您必须为您的菜单项使用动态生成的ID,以便每个片段都有其自己的项目ID。

+0

感谢您的详细回复和验证行为!我想避免使用'replace()',因为当我按下后退按钮时会导致我的片段重新加载。我会研究动态生成的菜单ID。 – wayway

+1

@WayWay动态设置菜单项ID可能会导致菜单中出现重复条目​​。如果你调用menu.clear(),那么你将只有最后添加的菜单的菜单ID,所以你仍然有问题。 – lionscribe

+1

@WayWay另一种可能的解决方案是以某种方式在活动中存储对“当前”片段的引用(可能通过'id'或'tag'),然后在'onOptionsItemSelected()'中检查是否是当前如果不是,则返回false。 –