dzada dzada - 4 months ago 48
Java Question

AdapterView.AdapterContextMenuInfo is null

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

Answer

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