Search code examples
androiddata-bindingandroid-lifecycle

Android Two-way Data-binding for RecyclerView Items


Binding model's data one-way to recyclerview items is easy as WE provide info to the item, but in some situations we need to fetch data (not events) from the item, e.g. list of people as items and entering the phone number for each one on those dudes. For this I need to bind the item's phone data two-way, but there is no lifecycleOwner here in the adapter.

inner class DataBindingViewHolder(private val binding: ViewDataBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(item: T) {
            binding.apply {
                setVariable(BR.item, item)
                executePendingBindings()
            }
        }
}

The observers's onChange() are not triggered. this is because there is no lifecycleOwner set inside binding.apply {} and passing fragment's owner causes a crash.


Solution

  • I have managed to do this by implementing LifecycleOwner in my BaseAdapter's DataBindingViewHolder. But there might be a lifecycle bug there. So use this with caution and I am accepting any notes on this implementation:

     inner class DataBindingViewHolder(private val binding: ViewDataBinding) :
        RecyclerView.ViewHolder(binding.root), LifecycleOwner {
    
        private val lifecycleRegistry = LifecycleRegistry(this)
    
        init {
            lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
        }
    
        fun onAppear() {
            lifecycleRegistry.currentState = Lifecycle.State.CREATED
            lifecycleRegistry.currentState = Lifecycle.State.STARTED
        }
    
        fun onDisappear() {
            lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
        }
    
        override fun getLifecycle(): Lifecycle {
            return lifecycleRegistry
        }
    
        fun bind(item: T) {
            binding.apply {
                lifecycleOwner = this@DataBindingViewHolder
                setVariable(BR.item, item)
                executePendingBindings()
                root.apply {
                    setOnClickListener {
                        onItemClicked?.invoke(item, this)
                    }
                    setOnLongClickListener {
                        onItemLongClicked?.invoke(item, this)
                        return@setOnLongClickListener true
                    }
                }
            }
    
        }
    }