LouisCAD / Splitties

A collection of hand-crafted extensions for your Kotlin projects.
https://splitties.louiscad.com
Apache License 2.0
2.53k stars 159 forks source link

ViewHolder safely use adapterPosition #239

Open vincent-paing opened 4 years ago

vincent-paing commented 4 years ago

ViewHolder has function that can get its position through adapterPosition. However on rare cases, user scroll, adapterPosition could return RecyclerView could return NO_POSITION, which is a -1. To safely use adapterPosition, we can check with

if (adapterPosition != RecyclerView.NO_POSITION

I came up with this extension function to safely use it without the hassle of if check

/**
 * Safely receive ViewHolder [ViewHolder.getBindingAdapter] without having tyo check for [RecyclerView.NO_POSITION].
 *
 * @param doOnNoPosition A function that is invoked when the position returns
 * @param doOnSafePosition A function that will be executed if the position is not [RecyclerView.NO_POSITION], position is passed into this function
 */
fun ViewHolder.withSafeBindingAdapterPosition(
  doOnNoPosition: (() -> (Unit)) = {
    //Do Nothing
  },
  doOnSafePosition: ((@ParameterName("position") Int) -> (Unit))
) {
  val position = bindingAdapterPosition
  if (position != RecyclerView.NO_POSITION) {
    doOnSafePosition.invoke(position)
  } else {
    doOnNoPosition.invoke()
  }
}
LouisCAD commented 4 years ago

From what I can read, this is not an issue in Splitties. If what you want is to make a proposal of a new extension for Splitties, please, be clear about it, and give a use case where appropriate (for the extension you showed, it is appropriate to give a use case as I never needed this so far), while keeping the details level in control.

vincent-paing commented 4 years ago

Sorry for the confusion caused on my part. I was proposing new extensions for Splitties. The use case would be just that it could cut down lines such as these

if (adapterPosition != RecyclerView.NO_POSITION) {
 //Lines of codes here
} else {
 //Lines of codes here
}

And allow easier usage of position safely. I've been using such extensions a lot on my projects, not sure if it might be necessary for others. Feel free to close it if you feel like it's not needed.

LouisCAD commented 4 years ago

I personally never needed to check the position of a ViewHolder, so I have trouble understanding in which case you'd need it.

Regardless, the method signature is not really simpler than an if to me, so it's unlikely I'll bring this to Splitties public API, but I'm curious where you'd need to get the position of a ViewHolder, and what you'd do when you don't have it or when you have it @vincent-paing.

vincent-paing commented 4 years ago

I personally never needed to check the position of a ViewHolder, so I have trouble understanding in which case you'd need it.

Maybe my personal preferences, I don't like putting setOnClickListener in onBindViewHolder because such listener doesn't need to binded each time holders are recycled. So I put them under onCreateViewHolder. This way, it's more performant since listener are not being added again and again. However onCreateViewHolder won't have position in its method signature since it's not tied to position.

In such case, I use this following code

val view = //inflate
val viewHolder = ViewHolder(view)
viewHolder.apply {
 itemView.setOnClickListener {
  if (holder.position != RecyclerView.NO_POSITION) {
   //do stuffs here
  }
 }
}
return viewHolder

And what you'd do when you don't have it or when you have it

It's a very very rare case and wouldn't happen unless you are updating the items in adapter frequently. Currently I only place Timber logs there but you can also do stuffs like providing error call back, showing "Item not exist" Toast etc.