Fragment 中的上下文菜单使用来自不同 Fragment 的 ListView: registerForContextMenu(getListView())
Posted
技术标签:
【中文标题】Fragment 中的上下文菜单使用来自不同 Fragment 的 ListView: registerForContextMenu(getListView())【英文标题】:Context Menu in Fragment uses ListView from a different Fragment: registerForContextMenu(getListView()) 【发布时间】:2014-09-25 14:52:11 【问题描述】:我已经尝试寻找解决方案,但没有找到任何符合我情况的解决方案。我有一个扩展 FragmentActivity 的 MainActivity 和多个 ListFragments。我将 PagerSlidingTabStrip 库用于幻灯片和 ViewPager。片段没有 XML 布局,它们只是返回 ListView 的 ListFragments,因此不需要布局。
这是一个音板应用程序,长按列表项允许用户将声音文件设置为铃声、通知或警报,或保存到 SD 卡。
现在,所有 Fragment 都可以正常加载自己的数据。一切似乎都很好,但是,当我在后台加载的 Fragment 上使用上下文菜单时,它似乎正在使用在它之前加载的第一个或上一个 Fragment 中的 ListView,它在创建时可见.
我的意思是,假设我的 MainActivity 启动,它加载 FragmentA,并且在后台 FragmentB 也被预加载。
在onActivityCreated方法中,对于两个Fragment,它都使用了registerForContextMenu(getListView())。
@Override
public void onActivityCreated(Bundle savedInstanceState)
super.onActivityCreated(savedInstanceState);
// Data loading etc
MyAdapter adapter = new MyAdapter(getActivity(),
R.layout.data_row, data);
setListAdapter(adapter);
registerForContextMenu(getListView());
但似乎正在发生的是 FragmentB 调用 registerForContextMenu(getListView()) 并且它似乎正在使用当前活动的 ListView,这是 FragmentA 的列表。
所以,假设我从上下文菜单中选择保存文件。我长按 FragmentB 的第一项,但它试图保存 FragmentA 的第一项。如果我只是点击列表项,它会按照您的预期播放它自己的声音,但上下文菜单命令使用预加载时可见的片段列表。
这里是 onCreateContextMenu。请注意,此时它在上下文菜单标题中使用正确的项目标题。
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo)
super.onCreateContextMenu(menu, v, menuInfo);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
menu.setHeaderTitle(data.get(info.position).getDataName());
MenuInflater inflater = this.getActivity().getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
这里是 onContextItemSelected。
@Override
public boolean onContextItemSelected(MenuItem item)
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int dataID = data.get(info.position).getDataID();
String dataName = data.get(info.position).getDataName();
Activity activity = getActivity();
if(activity instanceof MainActivity)
switch (item.getItemId())
case R.id.context_ringtone:
((MainActivity) activity).setRingtone(dataID, dataName);
return true;
case R.id.context_notification:
((MainActivity) activity).setNotification(dataID, dataName);
return true;
case R.id.context_alarm:
((MainActivity) activity).setAlarm(dataID, dataName);
return true;
case R.id.context_sd_card:
((MainActivity) activity).saveFile(dataID, dataName);
return true;
default:
return super.onContextItemSelected(item);
return super.onContextItemSelected(item);
这一切都按预期工作,除了预加载的 Fragments 使用了错误的 ListView。
所以我正在寻找一种方法来确保当 FragmentB 在后台加载时,当另一个 Fragment 处于活动状态时,FragmentB 应该为上下文菜单注册它自己的 ListView,而不是任何发生的活动的 ListView在当时可见。
我尝试过使用 MyFragment.this.getListView(),也尝试过使用 setUserVisibleHint 方法,但这些都没有帮助。我已经尝试在 onResume 中执行 registerForContextMenu(getListView()),希望它会在 Fragment 激活时重新注册正确的 ListView。
任何帮助将不胜感激,谢谢!
【问题讨论】:
【参考方案1】:我终于想通了!
事实证明,这不仅仅是为错误的 ListView 调用上下文菜单,而是为所有片段调用上下文菜单。
这是通过在 onContextItemSelected 方法中的 if 语句中使用 getUserVisibleHint() 解决的,因此如果调用上下文菜单的 Fragment 不可见,它将返回 false,但如果它是当前可见的 Fragment,它将执行正确的代码,意思是跳过不是预期片段的片段。我已经以不同的方式尝试过 getUserVisibleHint() ,但当时我并没有从正确的角度考虑这个问题。
这是解决方案的一个示例。
@Override
public boolean onContextItemSelected(MenuItem item)
if (getUserVisibleHint())
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int dataID = data.get(info.position).getDataID();
String dataName = data.get(info.position).getDataName();
Activity activity = getActivity();
if(activity instanceof MainActivity)
switch (item.getItemId())
case R.id.context_ringtone:
((MainActivity) activity).setRingtone(dataID, dataName);
return true;
case R.id.context_notification:
((MainActivity) activity).setNotification(dataID, dataName);
return true;
case R.id.context_alarm:
((MainActivity) activity).setAlarm(dataID, dataName);
return true;
case R.id.context_sd_card:
((MainActivity) activity).saveFile(dataID, dataName);
return true;
default:
return super.onContextItemSelected(item);
return false;
【讨论】:
有同样的问题,ViewPager 的活动,每个页面都有自己的 ListView。 getUserVisibleHint() 在这里可以解决问题。 这似乎不是最好的解决方案。在可以同时显示多个片段的应用程序中它会失败。【参考方案2】:不要使用registerForContextMenu(getListView())
,而是使用getListView().setOnCreateContextMenuListener()
下面是一个例子:
public class ListViewFragment extends Fragment implements AdapterView.OnItemLongClickListener
private int position;
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
super.onViewCreated(view, savedInstanceState);
getListView().setOnCreateContextMenuListener(this);
getListView().setOnItemLongClickListener(this);
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)
super.onCreateContextMenu(menu, v, menuInfo);
String title = mAdapter.getTitle(position);
menu.setHeaderTitle(title);
menu.add(0, MenuIds.play, 0, getString(R.string.play));
@Override
public boolean onContextItemSelected(MenuItem item)
Log.e("onContextItemSelected",String.valueOf(position));
return true;
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
this.position = position;
return false;
【讨论】:
My app calls setOnCreateContextMenuListener on the list view as you suggest, but even so, every fragment is notified when a context menu item is selected.以上是关于Fragment 中的上下文菜单使用来自不同 Fragment 的 ListView: registerForContextMenu(getListView())的主要内容,如果未能解决你的问题,请参考以下文章
如何在Fragment中使用Actionbar-Android开发问答
如何从 qgraphicsview 中的 qgraphicsitem 获取不同的上下文菜单?
android UI:底部菜单栏的学习与制作——Fragment碎片一