shafeeq
shafeeq

Reputation: 1589

Wrong item is getting selected in AutoCompleteTextView adapter

I am facing an issue in AutoCompleteTextView adapter. I have to create autocomplete adapter which will display the filtered contact list from the device. In my case, the filtering is working fine. But when I select an item from the list, the data set in the AutoCompleteTextView is from the original list, not from the filtered list. Can any one help me to resolve the issue?

Please find my adapter class below

class ContactListAdapter(private var ctx: Context, private var contacts: ArrayList<MobileContact>):
    ArrayAdapter<MobileContact>(ctx, R.layout.contact_item, contacts) {

    private var filter: ContactFilter? = null

    private class ViewHolder(view: View?) {
        var name: TextView? = null
        var number: TextView? = null

        init {
            name = view?.findViewById(R.id.contactName)
            number = view?.findViewById(R.id.contactNumber)
        }
    }

    private val filteredContacts = ArrayList<MobileContact>()

    override fun getCount() = filteredContacts.size

    override fun getFilter(): Filter {
        return if(filter == null)
            ContactFilter(this, contacts)
        else filter!!
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view: View
        val viewHolder: ViewHolder
        val contact = filteredContacts[position]

        val inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        if(convertView == null) {
            view = inflater.inflate(R.layout.contact_item, parent, false)
            viewHolder = ViewHolder(view)
            view.tag = viewHolder
        } else {
            view = convertView
            viewHolder = view.tag as ViewHolder
        }

        viewHolder.name?.text = contact.name
        viewHolder.number?.text = contact.number

        return view
    }

    @Suppress("UNCHECKED_CAST")
    class ContactFilter(private var adapter: ContactListAdapter, private var contacts: ArrayList<MobileContact>) : Filter() {
        private var filteredContacts = ArrayList<MobileContact>()

        override fun performFiltering(constraint: CharSequence?): FilterResults {
            filteredContacts.clear()
            val results = FilterResults()
            if(constraint == null || constraint.isEmpty()) {
                filteredContacts.addAll(contacts)
            } else {
                val filterPattern = constraint.toString().toLowerCase(Locale.ENGLISH).trim()
                for(contact in contacts) {
                    if(contact.name.toLowerCase(Locale.ENGLISH).contains(filterPattern) ||
                            contact.number.contains(filterPattern)) {
                        filteredContacts.add(contact)
                    }
                }
            }
            results.values = filteredContacts
            results.count = filteredContacts.size
            return results
        }

        override fun convertResultToString(resultValue: Any?): CharSequence {
            return (resultValue as MobileContact).number
        }

        override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
            adapter.filteredContacts.clear()
            adapter.filteredContacts.addAll(results?.values as ArrayList<MobileContact>)
            adapter.notifyDataSetChanged()
        }
    }
}

Upvotes: 0

Views: 156

Answers (1)

shafeeq
shafeeq

Reputation: 1589

After a lot of debugging, I resolved the issue. Here what I did is I removed the filtered results from the adapter. And the filter will be kept the whole data.

Please find the code below. Someone may have useful

class ContactListAdapter(private var ctx: Context, private var contacts: ArrayList<MobileContact>):
    ArrayAdapter<MobileContact>(ctx, R.layout.contact_item, contacts) {

    private var filter = ContactFilter()

    private class ViewHolder(view: View?) {
        var name: TextView? = null
        var number: TextView? = null

        init {
            name = view?.findViewById(R.id.contactName)
            number = view?.findViewById(R.id.contactNumber)
        }
    }

    override fun getCount() = contacts.size

    override fun getFilter(): Filter {
        return filter
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view: View
        val viewHolder: ViewHolder
        val contact = contacts[position]

        val inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        if(convertView == null) {
            view = inflater.inflate(R.layout.contact_item, parent, false)
            viewHolder = ViewHolder(view)
            view.tag = viewHolder
        } else {
            view = convertView
            viewHolder = view.tag as ViewHolder
        }

        viewHolder.name?.text = contact.name
        viewHolder.number?.text = contact.number

        return view
    }

    @Suppress("UNCHECKED_CAST")
    inner class ContactFilter : Filter() {
        private var filteredContacts = ArrayList<MobileContact>()
        private var origList = ArrayList<MobileContact>()

        override fun performFiltering(constraint: CharSequence?): FilterResults {
            if(origList.isEmpty())
                origList.addAll(contacts)

            filteredContacts.clear()
            val results = FilterResults()
            if(constraint == null || constraint.isEmpty()) {
                filteredContacts.addAll(origList)
            } else {
                val filterPattern = constraint.toString().toLowerCase(Locale.ENGLISH).trim()
                for(contact in origList) {
                    if(contact.name.toLowerCase(Locale.ENGLISH).contains(filterPattern) ||
                            contact.number.contains(filterPattern)) {
                        filteredContacts.add(contact)
                    }
                }
            }
            results.values = filteredContacts
            results.count = filteredContacts.size
            return results
        }

        override fun convertResultToString(resultValue: Any?): CharSequence {
            return (resultValue as MobileContact).number
        }

        override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
            contacts.clear()
            contacts.addAll(results?.values as ArrayList<MobileContact>)
            notifyDataSetChanged()
        }
    }
}

Upvotes: 0

Related Questions