2

I've been trying to implement recycling in my PagerAdapter, which I could do successfully thanks to this question however I'm running into a problem to cache the views with data binding.

I have tried like this, keeping a Stack<View>:

class CustomAdapter : PagerAdapter() {
    private var recycledViews: Stack<View> = Stack()

    var items: List<Item> = ArrayList()
        set(value) {
            field = value
            notifyDataSetChanged()
        }

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val binding = inflateOrRecycle(container)

        binding.item = items[position]
        binding.handler = this

        container.addView(binding.root)
        return binding.root
    }

    private fun inflateOrRecycle(container: ViewGroup): CustomBinding {
        val inflater = LayoutInflater.from(container.context)

        return if (recycledViews.isEmpty()) {
            CustomBinding.inflate(inflater, container, false)
        } else {
            val view = recycledViews.pop()
            CustomBinding.bind(view)
        }
    }

    override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
        val view = `object` as View

        container.removeView(view)
        recycledViews.add(view)
    }
}

However, whenever it tries to use a recycled view for the first time and calls CustomBinding.bind(view) it crashes because the view must have a tag. I've searched this, but none of the answers I've found have quite fixed my problem.

I've also tried keeping a Stack<CustomBinding>, but the problem is I'm not sure how to handle the destroyItem method. Because if I do:

override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
    val view = `object` as View

    container.removeView(view)
    recycledViews.add(CustomBinding.bind(view))
}

I'll still get the same error. How can I "recycle" data binding objects like this? Or, if I recycle the views themselves, how do I convert them back to binding objects?

AdamMc331
  • 16,492
  • 10
  • 71
  • 133

1 Answers1

1

You have done a simple mistake, I guess. You can correct me if I am wrong, I tried with this adapter and it worked.

val demoAdapter = object : PagerAdapter() {
        private var recycledViews: Stack<View> = Stack()

        var items: List<String> = ArrayList()
            set(value) {
                field = value
                notifyDataSetChanged()
            }

        override fun instantiateItem(container: ViewGroup, position: Int): Any {
            val binding = inflateOrRecycle(container)


            container.addView(binding.root)
            return binding.root
        }

        private fun inflateOrRecycle(container: ViewGroup): DemoItemBinding {
            val inflater = LayoutInflater.from(container.context)

            return if (recycledViews.isEmpty()) {
                DemoItemBinding.inflate(inflater, container, false)
            } else {
                val view = recycledViews.pop()
                val custBinding = DataBindingUtil.getBinding<DemoItemBinding>(view)
                if(custBinding == null)
                    DemoItemBinding.bind(view)
                else
                    custBinding
            }
        }

        override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
            val view = `object` as View

            container.removeView(view)
            recycledViews.add(view)
        }

        override fun isViewFromObject(view: View, `object`: Any): Boolean {
            return `object` is View && view.equals(`object`)
        }

        override fun getCount(): Int {
            return 4
        }
    }

The portion I changed from your code was this

return if (recycledViews.isEmpty()) {
            CustomBinding.inflate(inflater, container, false)
        } else {
            val view = recycledViews.pop()
            CustomBinding.bind(view)
        }

to

return if (recycledViews.isEmpty()) {
                DemoItemBinding.inflate(inflater, container, false)
            } else {
                val view = recycledViews.pop()
                val custBinding = DataBindingUtil.getBinding<DemoItemBinding>(view)
                if(custBinding == null)
                    DemoItemBinding.bind(view)
                else
                    custBinding
            }

I think, you were trying to bind to a view which already has a Binding attached to it. Thus it was giving you an error. What I have done is check for any previous binding, if it's there return the associated binding.

Debanjan
  • 2,817
  • 2
  • 24
  • 43