I just started using databinding
now I'm stuck implementing a click listener the databinding way in a recyclerView
.
I have it working like this:
@NonNull
@Override
public BookViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemBookCoversBinding binding = ItemBookCoversBinding.inflate(LayoutInflater.from(context), parent, false);
final BookViewHolder bookViewHolder = new BookViewHolder(binding);
bookViewHolder.binding.bookDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.deleteCover(bookViewHolder.getAdapterPosition());
}
});
bookViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.changeCover(bookViewHolder.getAdapterPosition());
}
});
return bookViewHolder;
}
which literally works fine but I'm not using databinding
for the clickListener
.
I have tried adding a variable position to my layout like this:
<data>
<variable
name="position"
type="int" />
<variable
name="listener"
type="....interfaces.Listener" />
</data>
<ImageView
android:id="@+id/book_cover"
coverImage="@{bookImages.storageRef}"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_green_dark"
android:onClick="@{() -> listener.changeCover(position)}"
android:src="@drawable/placeholder" />
and in the onCreateViewHolder
in Adapter this:
bookViewHolder.binding.setVariable(BR.position, bookViewHolder.getAdapterPosition());
or this:
binding.setPosition(bookViewHolder.getAdapterPosition());
The onClick
works as expected on both cases but the bookViewHolder.getAdapterPosition()
returns -1
,NO_POSITION
What am I missing here?
What is the best way to implement a databinding
onClickListener
in a RecyclerView
?
I have already something that works, but is not the databinding
way.
It does not work because you assign variables at view creation time. At this moment your ViewHolder
s don't have adapterPositions. I don't know how exactly they work, but whenever I tried to use it outside of click listeners, it always returned -1. They are not attached to the RecyclerView
at this moment, so you won't get it without some asynchronous work or layoutChangeListeners and it will probably always be -1 in onCreateViewHolder
The solution is to take your ViewHolder
's position from other place. You can get this with viewType
variable after overriding getItemViewType(int pos)
method like that:
@Override
public int getItemViewType(int position) {
return position;
}
@NonNull
@Override
public PlaylistViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewTypeButActuallyItIsPosition) {
...
binding.setPosition(viewTypeButActuallyItIsPosition);
...
}
Edit
One problem that you can face with such approach (and it seems to me you probably will) is that ImageView
s will have wrong positions set when your ViewHolders
have been recycled, as onBindViewHolder
methods will be called without calling onCreateViewHolder
, UI will be changed but the binding variable will stay the same, so the correct way would be assigning this position in onBindViewHolder
method. This means you should keep your binding in a ViewHolder
class and keep it public so you can access it in onBindViewHolder
@Override
public void onBindViewHolder(@NonNull YourViewHolder holder, int i) {
...
holder.binding.setPosition(i);
}