Android 片段中的上下文菜单使用来自不同片段的ListView:registerForContextMenu(getListView())

Android 片段中的上下文菜单使用来自不同片段的ListView:registerForContextMenu(getListView()),android,listview,android-fragments,fragment,contextmenu,Android,Listview,Android Fragments,Fragment,Contextmenu,我试图寻找解决办法,但没有找到任何符合我的情况。我有一个扩展FragmentActivity的MainActivity和多个ListFragments。我使用PagerSlidingTastrip库来创建幻灯片选项卡和一个ViewPager。片段没有XML布局,它们只是返回ListView的ListFragments,因此不需要布局 这是一款声板应用程序,长按列表项,用户可以将声音文件设置为铃声、通知或警报,或保存到SD卡 现在,所有片段都可以加载自己的数据。一切似乎都正常,但是,当我在后台加载

我试图寻找解决办法,但没有找到任何符合我的情况。我有一个扩展FragmentActivity的MainActivity和多个ListFragments。我使用PagerSlidingTastrip库来创建幻灯片选项卡和一个ViewPager。片段没有XML布局,它们只是返回ListView的ListFragments,因此不需要布局

这是一款声板应用程序,长按列表项,用户可以将声音文件设置为铃声、通知或警报,或保存到SD卡

现在,所有片段都可以加载自己的数据。一切似乎都正常,但是,当我在后台加载的片段上使用上下文菜单时,它似乎使用了在它之前加载的第一个或上一个片段的ListView,该片段在创建时是可见的

我的意思是,假设我的主活动开始,它加载FragmentA,在后台,FragmentB也被预加载

在onActivityCreated方法中,对于这两个片段,它都使用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);
}
除了预加载的片段使用了错误的ListView这一事实之外,所有这些都可以正常工作

因此,我要寻找的是一种方法,以确保当FragmentB在后台加载时,当另一个片段处于活动状态时,FragmentB应该为上下文菜单注册它自己的ListView,而不是在当时碰巧可见的任何活动的ListView

我尝试过使用MyFragment.this.getListView(),也尝试过使用setUserVisibleHint方法,但这些方法都没有帮助。我已经尝试在onResume中执行registerForContextMenu(getListView()),希望它在片段激活时重新注册正确的ListView


非常感谢您的帮助,谢谢

我终于找到了答案

事实证明,它不仅仅是为错误的ListView调用上下文菜单,而是为所有片段调用上下文菜单

这是通过在onContextItemSelected方法内的if语句中使用getUserVisibleHint()解决的,因此,如果调用上下文菜单的片段不可见,它将返回false,但如果它是当前可见的片段,它将执行正确的代码,意思是跳过不是预期片段的片段。我已经以不同的方式尝试过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;
}

使用
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;
         }
    }
公共类ListViewFragment扩展片段实现AdapterView.OnItemLongClickListener{
私人职位;
@凌驾
已创建公用void onview(@NonNull视图,@Nullable Bundle savedInstanceState){
super.onViewCreated(视图,savedInstanceState);
getListView().setOnCreateContextMenuListener(此);
getListView().setOnItemLongClickListener(此);
}
@凌驾
public void onCreateContextMenu(ContextMenu菜单,视图v,ContextMenu.ContextMenuInfo菜单信息){
super.onCreateContextMenu(menu,v,menuInfo);
字符串title=mAdapter.getTitle(位置);
菜单.设置标题(标题);
添加(0,MenuIds.play,0,getString(R.string.play));
}
@凌驾
公共布尔值onContextItemSelected(MenuItem项){
Log.e(“onContextItemSelected”,String.valueOf(position));
返回true;
}
@凌驾
公共布尔值长单击(AdapterView父项、视图、整型位置、长id){
这个位置=位置;
返回false;
}
}

也有同样的问题,活动与ViewPager有关,每个页面都有自己的ListView。getUserVisibleHint()在这里起作用。这似乎不是最好的解决方案。在一个可以同时显示多个片段的应用程序中,它将失败。我的应用程序会按照您的建议在列表视图上调用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;
         }
    }