user-44651
user-44651

Reputation: 4124

Using ViewBinding on an ArrayAdapter

I'm trying to refactor my app to use ViewBinding. I've gone through all the fragments and activities; however, I have an ArrayAdapter that I'm unsure of the proper convention to use view binding to prevent memory leaks.

What is the proper way to use a viewbinding in an ArrayAdapter?

I have been using this method for fragments:

private var _binding: BINDING_FILE_NAME? = null
private val binding get() = _binding!!

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    _binding = BINDING_FILE_NAME.inflate(inflater, container, false)
    return binding.root
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

I call my adapter like so:

   var myadapter : MyCustomAdapter = MyCustomAdapter(requireContext(), R.layout.row_autocomplete_item, myListOfStrings())

MyCustomAdapter class


class MyCustomAdapter(ctx: Context, private val layout: Int, private val allItems: List<String>) : ArrayAdapter<String>(ctx, layout, allItems) {

    var filteredItems: List<String> = listOf()

    override fun getCount(): Int = filteredItems.size

    override fun getItem(position: Int): String = filteredItems[position]


    @SuppressLint("SetTextI18n")
    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view = convertView ?: LayoutInflater.from(parent.context).inflate(layout, parent, false)

        val item = filteredItems[position]

        view.apply {
            // HERE IS WHERE I AM NEEDING TO BIND THE VIEW
            tvName?.text = item
        }

        return view
    }

    override fun getFilter(): Filter {
        return object : Filter() {
            override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults) {
                @Suppress("UNCHECKED_CAST")
                filteredItems = filterResults.values as List<String>
                notifyDataSetChanged()
            }

            override fun performFiltering(charSequence: CharSequence?): FilterResults {
                val queryString = charSequence?.toString()?.lowercase(Locale.ROOT)

                val results = FilterResults()

                results.values = if (queryString == null || queryString.isEmpty())
                    allItems
                else
                    allItems.filter {
                        it.lowercase(Locale.ROOT).contains(queryString)
                    }
                return results
            }
        }
    }

}

Upvotes: 10

Views: 4502

Answers (3)

Mudit Goel
Mudit Goel

Reputation: 354

For GridView adapters or custom adapter following code worked for me :

override fun getView(position: Int, convertView: View?, container: ViewGroup?): View {
    val binding = convertView?.tag as? MenuItemBinding ?:
    MenuItemBinding.inflate(LayoutInflater.from(ctx), container, false)

    val menuItem = menuList[position]
    binding.txtVw.text = menuItem.title
    binding.imgVwIcon.setImageResource(menuItem.iconId)
    return binding.root
}

MenuItemBinding is on the basis of the name of the layout file here the layout file name is 'menu_item.xml' hence no need to define layout files as well.

Upvotes: 0

Roman
Roman

Reputation: 305

Based on this answer, got this:

If convertView is not null, then bind to it. Inflate otherwise.

override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
    val binding: MyLayoutBinding =
        if (convertView != null) MyLayoutBinding.bind(convertView)
        else MyLayoutBinding.inflate(LayoutInflater.from(context), parent, false)

    // use binding
    val item = getItem(position)
    binding.text = item.name

    return binding.root
}

Upvotes: 6

Mohamed Ashik
Mohamed Ashik

Reputation: 362

I did like this, its working. But Im not sure, whether it is correct way or not

 override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
    val binding: LayoutCustomSpinnerBinding
    var row = convertView

    if (row == null) {
        val inflater =
            context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        binding = LayoutCustomSpinnerBinding.inflate(inflater, parent, false)
        row = binding.root
    } else {
        binding = LayoutCustomSpinnerBinding.bind(row)
    }
    binding.txtContent.text = spinnerList[position].ValueData
    return row
}

Upvotes: 7

Related Questions