Skip to content

Instantly share code, notes, and snippets.

@ShinichiroFunatsu
Last active July 22, 2020 07:14
Show Gist options
  • Save ShinichiroFunatsu/56245dcaf1d91b4cd40b3907c5c1df0e to your computer and use it in GitHub Desktop.
Save ShinichiroFunatsu/56245dcaf1d91b4cd40b3907c5c1df0e to your computer and use it in GitHub Desktop.
[Android][RecyclerView] My Easy DiffUtil function for RecyclerView.
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
// allocate first
val defaultCallback = MutableDiffCallback()
fun RecyclerView.Adapter<*>.calculateDiff(
old: List<*>,
new: List<*>,
callback: MutableDiffCallback = defaultCallback,
detectMoves: Boolean = false
) {
callback.new = new
callback.old = old
DiffUtil.calculateDiff(callback, detectMoves)
.dispatchUpdatesTo(this)
}
open class MutableDiffCallback(
var old: List<*>? = null,
var new: List<*>? = null
) : DiffUtil.Callback() {
override fun getOldListSize() = old?.size ?: 0
override fun getNewListSize() = new?.size ?: 0
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val o = old ?: return false
val n = new ?: return false
// warn: not equals
return o[oldItemPosition] === n[newItemPosition]
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val o = old ?: return false
val n = new ?: return false
return o[oldItemPosition] == n[newItemPosition]
}
}
@ShinichiroFunatsu
Copy link
Author

and Delegates.observable combo!

sealed class  MyListEvent {
    data class Add(val position: Int) : MyListEvent()
    data class Remove(val position: Int) : MyListEvent()
}

class MyAdapter(
    dafaultValues: List<MyData>,
    private val lifecycleOwner: LifecycleOwner,
    private val event: LiveData<MyListEvent>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private var cachedValues: List<MyData> by Delegates.observable(
        initialValue = defaultPages,
        onChange = { _, old, new -> calculateDiff(old, new) }
    )
    
    init {
        event.observe(lifecycleOwner) {
            when (it) {
                is MyListEvent.Add -> {
                    val adddingPosition = it.position
                    val new = cachedValues.toMutableList()
                    new.add(adddingPosition, MyData(id=uuid()))
                    cachedValues = new
                }
                is MyListEvent.Remove -> {
                    val new = cachedValues.toMutableList()
                    new.removeAt(it.position)
                    cachedValues = new
                }
            }
        }
    }
    ...
}

@ShinichiroFunatsu
Copy link
Author

smarter than using setOnClickListener in onBindViewHolder!!

interface OnClickPositionListener {
    fun onClickWithPosition(position: Int)
}

@BindingAdapter("app:onClickWithPosition")
fun onClickWithPosition(view: View, listener: OnClickPositionListener) {
    view.setOnClickListener {
        val viewHolder = view.tag as? RecyclerView.ViewHolder ?: return@setOnClickListener
        val position = viewHolder.adapterPosition
        listener.onClickWithPosition(position)
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment