Notify RecyclerView On a Specific Item Update

Occasionally when working with RecyclerView, we want to be able to notify on a specific update. We want to know the item position in the list, as well as which update was it (insert, remove, change). Maybe there’s some more information we want to pass about this update. For example, a reason for the change, or the originated screen, or the date it occurred at.

class CallRequestUiModel : ViewModel() {
lateinit var toPhone: String
lateinit var fromPhone: String
val actions = ListLiveData<NccoAction>()
}
class ListLiveData<T> : LiveData<ListHolder<T>>() {}
data class ListHolder<T>(val list: MutableList<T> = mutableListOf()) {
var indexChanged: Int = -1
var updateType: UpdateType? = null
}
private enum class UpdateType {
INSERT, REMOVE, CHANGE
}
private enum class UpdateType {   abstract fun notifyChange(
adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>,
indexChanged: Int
)
INSERT {
override fun notifyChange(
adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>,
indexChanged: Int) = adapter.notifyItemInserted(indexChanged)
},

REMOVE {
override fun notifyChange(
adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>,
indexChanged: Int) = adapter.notifyItemRemoved(indexChanged)
},
CHANGE {
override fun notifyChange(
adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>,
indexChanged: Int) = adapter.notifyItemChanged(indexChanged)
};

}
data class ListHolder<T>(val list: MutableList<T> = mutableListOf()) {
var indexChanged: Int = -1
private var updateType: UpdateType? = null

//...

fun applyChange(adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>) {
updateType?.notifyChange(adapter, indexChanged)
}
uiModel.actions.observe(this, this)
override fun onChanged(value: ListHolder<NccoAction>?) {
list.adapter?.let {
value?.applyChange(it)
}
}
fun addAction(action: NccoAction) {
uiModel.actions.addItem(action)
}
class ListLiveData<T> : LiveData<ListHolder<T>>() {

//...

fun addItem(item: T, position: Int = value?.size() ?: 0) {
value?.addItem(position, item)
value = value

}

fun removeItemAt(position: Int) {
value?.removeItemAt(position)
value = value
}


fun setItem(position: Int, item: T) {
value?.setItem(position, item)
value = value
}


}
From source code of LiveData.java@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
class ListLiveData<T> : LiveData<ListHolder<T>>() {

val size: Int get() {
return value?.size() ?: -1
}
operator fun get(position: Int): T? {
return value?.list?.get(position)
}

}
override fun getItemCount(): Int {
return actions.size
}
override fun onBindViewHolder(holder: NccoCompVH, index: Int) {
actions[index]?.let { holder.bind(it) }
}

Let’s see the entire flow

That’s it!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Britt Barak

Product manager @ Facebook. Formerly: DevRel / DevX ; Google Developer Expert; Women Techmakers Israel community lead.