Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Context Menu in Fragment uses ListView from a different Fragment: registerForContextMenu(getListView())

I've tried searching for solutions to this but have not found anything that matches my situation. I have a MainActivity which extends FragmentActivity, and multiple ListFragments. I use the PagerSlidingTabStrip library for slidetabs, and a ViewPager. Fragments don't have an XML layout, they are just ListFragments which returns a ListView so a layout was not needed.

It is a soundboard app, with long press on a list item allowing the user to set a sound file as their ringtone, notification or alarm, or to save to SD card.

Now, all Fragments load their own data just fine. Everything seems ok, however, when I use the context menu on a Fragment that was loaded in the background, it seems to be using the ListView from the first or previous fragment that was loaded before it, the one that was visible when it was created.

What I mean is, say my MainActivity starts, it loads FragmentA, and in the background FragmentB gets preloaded also.

In the onActivityCreated method, for both Fragments, it uses 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());
}

But what seems to be happening is that FragmentB calls registerForContextMenu(getListView()) and it seems to be taking the currently active ListView, which is the list for FragmentA.

So, say I choose to save a file from the context menu. I long press on the first item of FragmentB, but it tries to save the first item of FragmentA. If I just tap the list item, it plays it's own sound as you would expect, but context menu commands use the list of the Fragment that was visible when it was pre-loaded.

Here is the onCreateContextMenu. Note, at this point it uses the correct item Title in the context menu Title.

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

And here is the 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);
}

This all works as expected, apart from the fact that preloaded Fragments use the wrong ListView.

So what I am looking for, is a way to make sure that when FragmentB is loaded in the background, while another Fragment is active, FragmentB should be registering it's own ListView for the context menu, and not whichever activity's ListView which happened to be visible at the time.

I've tried using MyFragment.this.getListView(), and I've tried using the setUserVisibleHint method, but these didn't help. I've tried doing the registerForContextMenu(getListView()) in onResume, hoping it would re-register the correct ListView when the Fragment became active.

Any help would be hugely appreciated, thanks!

like image 565
Orcrist666 Avatar asked Aug 02 '14 15:08

Orcrist666


1 Answers

I managed to figure this out finally!

It turns out it wasn't just calling the context menu for the wrong ListView, the context menu was being called for ALL fragments.

This was solved by using getUserVisibleHint() in an if statement within the onContextItemSelected method, so that if the Fragment the context menu was called for was not visible, it would return false, but if it was the currently visible Fragment, it would execute the proper code, meaning is skips over Fragments that are not the intended Fragment. I had tried getUserVisibleHint() already in a different way but I wasn't thinking about the problem from the right angle then.

Here's an example of the solution.

@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;
}
like image 171
Orcrist666 Avatar answered Oct 11 '22 14:10

Orcrist666