简体   繁体   中英

Getting an adapter instance from a ViewHolder

I'm trying to create a contextual floating menu with the information (position,id,etc) of the selected menu to be accessible inside the overridden method onContextItemSelected in my Fragment.

So I have a custom adapter extending from RecyclerView.Adapter<ViewHolder> and a custom ViewHolder class in separate file. I registered my click listener and provided its handler inside the custom ViewHolder class.

Since I need to send the ViewHolder information back to my Fragment when the event is fired, I need to have a reference to my Adapter because my fragment has the adapter object reference but not viewholder object reference . So in instantiation stage of the custom ViewHolder (because there is no method to get Adapter reference from ViewHolder class), I pass the adapter reference to constructor of the custom ViewHolder for the use in its handler so I can call this reference inside the ViewHolder class to pass the information to Adapter from ViewHolder , and finally from Adapter to Fragment .

My question is, is there a better practice or a general approach by still keeping the handler inside the ViewHolder ? In my case, I notice every ViewHolder instance will have to keep a reference to adapter, which consumes memory. Is there any conflict that may arise in the future by doing it the way I listed above?

Maybe I'm not understanding well your pattern, but the reference you are looking for, it is already there.

The fragmens knows the adapter reference, and the adapter knows your viewholder. Use getAdapterPosition() to get that reference to your Object

Suppose to have a ArrayList<String> named list in your RecyclerView.Adapter<ViewHolder> : this code, for example, shows a Toast in the Fragment with the value of the clicked String

public ViewHolder( View itemView) {

    super(itemView);

    itemView.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            String myValue = list.get( getAdapterPosition() ); // your object 
            Toast.makeText(activity, myValue, Toast.LENGTH_SHORT).show();
        }
    });

}

Stumbled upon the same problem. The two variants give the same result, without using static references:

Suppose you have an ItemObjects class with name, price, address etc variables

  1. ViewHolder as external class:

In the Adapter, attach the ArrayList as Tag to the layoutView :

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyViewHolders> {

private List<ItemObjects> itemList;
private Context context;

public MyRecyclerViewAdapter(Context context, List<ItemObjects> itemList) {
    this.itemList = itemList;
    this.context = context;
}

@Override
public MyViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {

    View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_list_cell, parent, false);
    layoutView.setTag(itemList);
    return new MyViewHolders(layoutView);
}
}

Then, in the ViewHolder:

public class MyViewHolders extends RecyclerView.ViewHolder implements View.OnClickListener {

public MyViewHolders(View itemView) {
    super(itemView);
    itemView.setOnClickListener(this);
    //................
 }

@Override
public void onClick(View view) {

    Log.d(TAG, "onClick: itemName " + ((ArrayList<ItemObjects>) itemView.getTag())
            .get(getAdapterPosition()).getItemName());
 }
}
  1. Move the ViewHolder back as inner class into the Adapter. This way you can access the ArrayList directly :

     public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyViewHolders> { private static List<ItemObjects> itemList; //........................ public static class MyViewHolders extends RecyclerView.ViewHolder implements View.OnClickListener { //....................... @Override public void onClick(View view) { Intent intent = new Intent(view.getContext(), DetailActivity.class); Log.d(TAG, "onClick: itemName " + itemList.get(getAdapterPosition()).getItemName()); view.getContext().startActivity( new Intent(view.getContext(), DetailActivity.class)); } } }

    In my case, i start an Activity onClick and both variants work. In your case it would be better to use an inner class and access it through MyRecyclerViewAdapter.MyViewHolders

Pass the adapter in the constructor of the view holder

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_layout, parent, false);
    return new MyViewHolder(this, view);
}

You may pass the adapter in the view holder constructor as Blake mentioned. However, if the view holder class is an inner class of the Adapter you may access methods of the adapter directly without needing to pass a reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM