1

Here is my problem, I have this architecture of class :

  • Activity
    • Fragment
      • RecyclerView (which has an Adapter)

The adapter:

  • has a class ViewHolder:

    public static class NoteViewHolder extends RecyclerView.ViewHolder
    implements View.OnCreateContextMenuListener{
      TextView noteName;
    
      public NoteViewHolder(View itemView) {
    
        super(itemView);
        noteName = (TextView)itemView.findViewById(R.id.note_name);
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {/**/}
        });
        itemView.setOnCreateContextMenuListener(this);
    
      }
    
    @Override
    public void onCreateContextMenu(ContextMenu contextMenu, View view,
        ContextMenu.ContextMenuInfo contextMenuInfo) {
    
        contextMenu.setHeaderTitle("Select The Action");
        contextMenu.add(0,666,0,"Delete Note");
    }
    

    }

The fragment

overrrides onContextItemSelected(MenuItem item){
    //info is null
    AdapterView.AdapterContextMenuInfo info =
        (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
}

It also calls

    registerForContextMenu(recyclerView);

The sequence

  1. I long click on the NoteViewHolder, it opens the context menu
  2. I select "Delete"
  3. OnCreateContextMenu is called with contextMenuInfo == null
  4. onSelectedContextItem is called with item.getMenuInfo() == null

How can i get the menuInfo non null?

Shoud i create myself the menu info, and if so where?

PS, I've seen this post: How to create context menu for RecyclerView , i don't see the answer to this

PS2 I've also read this: http://androidheight.blogspot.fr/2015/03/recyclerview-widget-example-in-android.html, and to me the line new RecyclerAdapter().info = menuInfo; seems wrong

thank you

Community
  • 1
  • 1
dzada
  • 5,344
  • 5
  • 29
  • 37

2 Answers2

0

You need to call the registerForContextMenu() in the activity on the RecyclerView.

shine_joseph
  • 2,922
  • 4
  • 22
  • 44
  • activity or fragment – shine_joseph Jul 28 '16 at 12:28
  • can you take a look at this example http://androidheight.blogspot.in/2015/03/recyclerview-widget-example-in-android.html – shine_joseph Jul 28 '16 at 12:30
  • I called that in the fragment, already did, see PS 2 (this line: `new RecyclerAdapter().info = contextMenuInfo`seems bad – dzada Jul 28 '16 at 12:31
  • This is a completly different implem, I'll try it. but why is the other wrong?? Also this implementation exposes the position and the id publicly which seems wrong too – dzada Jul 28 '16 at 12:34
0

here is a solution i considered clean enough and implemented for that.

In the Adapter, i create an interface to be implemented (by another class, like the activity or my fragment in my case).

I pass the interface implementation to the CTOR of the adapter. It could be passed differently, this is just a choice here because i create the adapter in the fragment or the activity so anyway i can pass the interface implementation right away. This interface can have the methods you want.

public interface  NoteListCommandListener{
    void updateList();
    void remove(Note n);
}
RVNoteAdapter(NoteListCommandListener noteListCommandListener){
    super();
    mNoteListCommandListener = noteListCommandListener;
}

I modify the onBindViewHolder method to pass the interface implementation to every viewholder from the adapter.

@Override
public void onBindViewHolder(NoteViewHolder personViewHolder, int i) {

    String name = notes.get(i).name;
    personViewHolder.noteName.setText(name);
    personViewHolder.noteListCommandListener= mNoteListCommandListener;
}

Then in the view holder CTOR, i use setOnCreateContextMenuListener, i specify the class locally because when i call setOnMenuItemClickListener i still have access to noteListCommandListener and i can call any function of it directly.

public static class NoteViewHolder extends RecyclerView.ViewHolder
{
    TextView noteName;
    NoteListCommandListener noteListCommandListener;
    public NoteViewHolder(View itemView) {

        super(itemView);
        noteName = (TextView)itemView.findViewById(R.id.note_name);
        itemView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
            @Override
            public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
                contextMenu.setHeaderTitle("Select The Action");
                contextMenu.add(0,42,0,"Delete Note").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem menuItem) {
                        noteListCommandListener.remove(n);
                        return true;
                    }
                });


            }
        });


        }


}

Advantage the whole context menu of the view holder is coded in the view holder, it is simple. Disadvantage it not well separated, if you needed to change of context menu dynamically (not my case). If you do, you could avoid to define the 2 class locally and pass class define outside this scope by passing the proper arguments in the CTORS.

Thank you everyone for your advices

dzada
  • 5,344
  • 5
  • 29
  • 37