Skip to content

Instantly share code, notes, and snippets.

@cmorigaki
Last active February 10, 2021 14:10
Show Gist options
  • Select an option

  • Save cmorigaki/67a19b0866ca3b57af076062a89930c4 to your computer and use it in GitHub Desktop.

Select an option

Save cmorigaki/67a19b0866ca3b57af076062a89930c4 to your computer and use it in GitHub Desktop.
[Nested RecyclerView State] - View recreation or refresh list
abstract class NestedRecyclerViewStateRecoverAdapter<T, VH : RecyclerView.ViewHolder>(
diffUtil: DiffUtil.ItemCallback<T>
) : ListAdapter<T, VH>(diffUtil) {
private val layoutManagerStates = hashMapOf<String, Parcelable?>()
private val visibleScrollableViews = hashMapOf<Int, ViewHolderRef>()
@CallSuper
override fun onViewRecycled(holder: VH) {
if (holder is NestedRecyclerViewViewHolder) {
// Save the scroll position state (LayoutManager state)
val state = holder.getLayoutManager()?.onSaveInstanceState()
layoutManagerStates[holder.getId()] = state
// State saved and view is not visible
visibleScrollableViews.remove(holder.hashCode())
}
super.onViewRecycled(holder)
}
@CallSuper
override fun onBindViewHolder(holder: VH, position: Int) {
if (holder is NestedRecyclerViewViewHolder) {
holder.getLayoutManager()?.let {
// Retrieve and set the saved LayoutManager state
val state: Parcelable? = layoutManagerStates[holder.getId()]
if (state != null) {
it.onRestoreInstanceState(state)
} else {
// We need to reset the scroll position when no state needs to be restored
it.scrollToPosition(0)
}
}
visibleScrollableViews[holder.hashCode()] = ViewHolderRef(
holder.getId(),
WeakReference(holder as NestedRecyclerViewViewHolder)
)
}
}
@CallSuper
override fun submitList(list: List<T>?) {
// We need to save the state from visible views before updating/setting the list to preserve
// their states
saveState()
super.submitList(list)
}
private fun saveState() {
visibleScrollableViews.values.forEach { item ->
item.reference.get()?.let {
layoutManagerStates[item.id] = it.getLayoutManager()?.onSaveInstanceState()
}
}
visibleScrollableViews.clear()
}
fun clearState() {
layoutManagerStates.clear()
visibleScrollableViews.clear()
}
private data class ViewHolderRef(
val id: String,
val reference: WeakReference<NestedRecyclerViewViewHolder>
)
}
// ViewHolders containing a RecyclerView should inherit this interface.
// An alternative solution could be manually searching if the view constains a RecyclerView
interface NestedRecyclerViewViewHolder {
fun getId(): String
fun getLayoutManager(): RecyclerView.LayoutManager?
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment