As title says. ListAdapter on a ViewPager2 that uses Multiple View Holder is calling onBindViewHolder twice after clicking a button which forcefully refreshes the data changing the model.isStylusInputEnabled from either true or false. Here are the logs for a single ViewHolder named FirstViewHolder notice that isStylusInputEnabled for both ViewHolder is different. Which causes a problem as it resets my UI back to false even if I set it to true
2022-04-19 08:23:07.437 8667-8667/com.sample.dev D/TEST: load onBindViewHolder model.isStylusInputEnabled true this FirstViewHolder{e930e86 position=0 id=-1, oldPos=-1, pLpos:-1 not recyclable(1) no parent}}
2022-04-19 08:23:07.496 8667-8667/com.sample.dev D/TEST: load onBindViewHolder model.isStylusInputEnabled false this FirstViewHolder{843d958 position=0 id=-1, oldPos=-1, pLpos:-1 scrap [changeScrap] tmpDetached not recyclable(3) no parent}}
ListAdapter Code
class MultipleViewAdapter(
val firstFlow: Flow<List<FirstModel>>,
val secondFlow: Flow<List<SecondModel>>,
val thirdFlow: Flow<List<ThirdModel>>) : ListAdapter<ParentModel, RecyclerView.ViewHolder>(DefaultDiffUtil<ParentModel>()) {
companion object {
const val VIEW1 = 0
const val VIEW2 = 1
const val VIEW3 = 2
}
private val scope = CoroutineScope(Dispatchers.Main)
var onRemarksChangeListener: OnRemarksChangeListener? = null
fun interface OnRemarksChangeListener {
fun onChange(position: Int, value: String)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when(viewType) {
VIEW1 -> FirstViewHolder(ItemFirstBinding.inflate(LayoutInflater.from(parent.context), parent, false))
VIEW2 -> SecondConvectionViewHolder(ItemSecondBinding.inflate(LayoutInflater.from(parent.context), parent, false))
else -> ThirdViewHolder(ItemThirdBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
holder.setIsRecyclable(false)
when(holder) {
is FirstViewHolder -> holder.bind(position)
is SecondViewHolder -> holder.bind(position)
is ThirdViewHolder -> holder.bind(position)
}
}
//necessary for onBindViewHolder to render position correctly
override fun getItemViewType(position: Int): Int {
return getItem(position).pageType
}
//necessary for onBindViewHolder to render position correctly
override fun getItemId(position: Int): Long {
return position.toLong()
}
fun onDestroy() {
scope.cancel()
}
inner class FirstViewHolder(private val _binding: ItemFirstBinding) : RecyclerView.ViewHolder(_binding.root), StylusInput {
private val _adapter by lazy {
FirstAdapter()
}
override val pathCollection: List<List<Pair<Float, Float>>>
get() = _binding.canvas.pathCollection
override var isEnabled: Boolean = false
set(value) {
with(_binding) {
container.isScrollable = !value
canvas.isWritable = value
}
field = value
}
fun bind(position: Int) {
val model = getItem(position)
Log.d("TEST", "load onBindViewHolder ${model} model.isStylusInputEnabled ${model.isStylusInputEnabled} this ${this}}")
isEnabled = model.isStylusInputEnabled
_binding.canvas.loadPathCollection(model.stylusInput)
_binding.rvFirst.adapter = _adapter
scope.launch {
firstFlow.collectLatest {
_adapter.submitList(it) {}
}
_binding.rvFirst.viewTreeObserver.addOnDrawListener {
_binding.canvas.refresh(model.stylusInput)
}
}
}
}
inner class SecondViewHolder(private val _binding: ItemSecondBinding) : RecyclerView.ViewHolder(_binding.root), StylusInput {
private val _adapter by lazy {
SecondAdapter()
}
override val pathCollection: List<List<Pair<Float, Float>>>
get() = _binding.canvas.pathCollection
override var isEnabled: Boolean = false
set(value) {
with(_binding) {
container.isScrollable = !value
canvas.isWritable = value
}
field = value
}
fun bind(position: Int) {
val model = getItem(position)
isEnabled = model.isStylusInputEnabled
_binding.canvas.loadPathCollection(model.stylusInput)
_binding.rvSecond.adapter = _adapter
scope.launch {
secondFlow.collectLatest {
_adapter.submitList(it)
}
_binding.rvSecond.viewTreeObserver.addOnDrawListener {
_binding.canvas.refresh(model.stylusInput)
}
}
}
}
inner class ThirdViewHolder(private val _binding: ItemThirdBinding) : RecyclerView.ViewHolder(_binding.root), StylusInput {
private val _adapter by lazy {
ThirdAdapter()
}
override val pathCollection: List<List<Pair<Float, Float>>>
get() = _binding.canvas.pathCollection
override var isEnabled: Boolean = false
set(value) {
with(_binding) {
container.isScrollable = !value
canvas.isWritable = value
}
field = value
}
fun bind(position: Int) {
val model = getItem(position)
isEnabled = model.isStylusInputEnabled
_binding.canvas.loadPathCollection(model.stylusInput)
_binding.rvThird.adapter = _adapter
scope.launch {
thirdFlow.collectLatest {
_adapter.submitList(it)
}
_binding.rvThird.viewTreeObserver.addOnDrawListener {
_binding.canvas.refresh(model.stylusInput)
}
}
}
}
}