Reputation: 4124
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
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
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
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