It's always complicated to say what the "right approach" is, it can be better in one case and worse in others.
However, the onClickListener
is assigned to view . Who is responsible for giving view to adapter is ViewHolder class.
I think that should be where they should be attributed.
On the other hand, assigning "listeners" to onBindViewHolder()
will cause them to be assigned whenever a line appears in RecyclerView.
By assigning them in the ViewHolder constructor they will be reused, being assigned only once.
To get the position (1) use the getAdapterPosition () .
public static class MyViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener{
private final ImageView imageView;
public MyViewHolder(View v) {
super(v);
imageView = (ImageView) v.findViewById(R.id.imageView);
//Atribui o listener ao layout da linha.
v.setOnClickListener(this);
// no entanto ele pode ser aplicado a qualquer uma das views dele.
//imageView.setOnClickListener(this);
}
//Implementa View.OnClickListener
@Override
public void onClick(View v) {
Log.d(TAG, "Elemento " + getAdapterPosition() + " clicado.");
}
}
The onCreateViewHolder()
of adapter would look like this:
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.row_item, viewGroup, false);
return new MyViewHolder(v);
}
The onBindViewHolder()
method should only assign the values to views .
This approach can be improved so that the code to be executed when an item is clicked is external to the adapter .
Define an interface to be implemented by the class that will execute the code when an item is clicked:
public interface ItemClickListener {
void onItemClick(int position);
}
Add an attribute and its setter to save an instance that implements this interface:
private static ItemClickListener itemClickListener;
public void setOnItemClickListener(ItemClickListener itemClickListener){
this.itemClickListener = itemClickListener;
}
Change the ViewHolder to call the onItemClick()
method of this instance instead of implementing the code that handles the click.
public class MyViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener{
private final ImageView imageView;
public MyViewHolder(View v) {
super(v);
imageView = (ImageView) v.findViewById(R.id.imageView);
//Atribui o listener ao layout da linha.
v.setOnClickListener(this);
// no entanto ele pode ser aplicado a qualquer uma das views dele.
//imageView.setOnClickListener(this);
}
//Implementa View.OnClickListener
@Override
public void onClick(View v) {
if(itemClickListener != null) {
itemClickListener.onItemClick(getAdapterPosition());
}
}
}
Now it is possible to declare the code to execute when an item is clicked, where the adapter is instantiated
adapter.setOnItemClickListener(new ItemClickListener() {
@Override
public void onItemClick(int position) {
Log.d(TAG, "Elemento " + position + " clicado.");
}
});
(1) - Justified by this excerpt from documentation :
(...) Sometimes, you may need to get the exact adapter position of some actions in response to user events. In that case, you should use this method which will calculate the Adapter position of the ViewHolder.
(...) Sometimes it may be necessary to get the exact position of the adapter to do some actions in response to user events. In this case, you should use this method that will calculate the position of the ViewHolder on the adapter.