Android AutoCompleteTextView with Custom Adapter filtering not working Android AutoCompleteTextView with Custom Adapter filtering not working android android

Android AutoCompleteTextView with Custom Adapter filtering not working


I have to over-ride the getFilter() method of the Adapter

Here is the code which worked for me, thanks to sacoskun

public class CustomerAdapter extends ArrayAdapter<Customer> {    private final String MY_DEBUG_TAG = "CustomerAdapter";    private ArrayList<Customer> items;    private ArrayList<Customer> itemsAll;    private ArrayList<Customer> suggestions;    private int viewResourceId;    public CustomerAdapter(Context context, int viewResourceId, ArrayList<Customer> items) {        super(context, viewResourceId, items);        this.items = items;        this.itemsAll = (ArrayList<Customer>) items.clone();        this.suggestions = new ArrayList<Customer>();        this.viewResourceId = viewResourceId;    }    public View getView(int position, View convertView, ViewGroup parent) {        View v = convertView;        if (v == null) {            LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);            v = vi.inflate(viewResourceId, null);        }        Customer customer = items.get(position);        if (customer != null) {            TextView customerNameLabel = (TextView) v.findViewById(R.id.customerNameLabel);            if (customerNameLabel != null) {//              Log.i(MY_DEBUG_TAG, "getView Customer Name:"+customer.getName());                customerNameLabel.setText(customer.getName());            }        }        return v;    }    @Override    public Filter getFilter() {        return nameFilter;    }    Filter nameFilter = new Filter() {        @Override        public String convertResultToString(Object resultValue) {            String str = ((Customer)(resultValue)).getName();             return str;        }        @Override        protected FilterResults performFiltering(CharSequence constraint) {            if(constraint != null) {                suggestions.clear();                for (Customer customer : itemsAll) {                    if(customer.getName().toLowerCase().startsWith(constraint.toString().toLowerCase())){                        suggestions.add(customer);                    }                }                FilterResults filterResults = new FilterResults();                filterResults.values = suggestions;                filterResults.count = suggestions.size();                return filterResults;            } else {                return new FilterResults();            }        }        @Override        protected void publishResults(CharSequence constraint, FilterResults results) {            ArrayList<Customer> filteredList = (ArrayList<Customer>) results.values;            if(results != null && results.count > 0) {                clear();                for (Customer c : filteredList) {                    add(c);                }                notifyDataSetChanged();            }        }    };}


This is my solution. I feel like it's a bit cleaner (doesn't use 3 separate, confusing ArrayLists) than the accepted one, and has more options. It should work even if the user types backspace, because it doesn't remove the original entries from mCustomers (unlike the accepted answer):

public class CustomerAdapter extends ArrayAdapter<Customer> {    private LayoutInflater layoutInflater;    List<Customer> mCustomers;    private Filter mFilter = new Filter() {        @Override        public String convertResultToString(Object resultValue) {            return ((Customer)resultValue).getName();        }        @Override        protected FilterResults performFiltering(CharSequence constraint) {            FilterResults results = new FilterResults();            if (constraint != null) {                ArrayList<Customer> suggestions = new ArrayList<Customer>();                for (Customer customer : mCustomers) {                    // Note: change the "contains" to "startsWith" if you only want starting matches                    if (customer.getName().toLowerCase().contains(constraint.toString().toLowerCase())) {                        suggestions.add(customer);                    }                }                results.values = suggestions;                results.count = suggestions.size();            }            return results;        }        @Override        protected void publishResults(CharSequence constraint, FilterResults results) {            clear();            if (results != null && results.count > 0) {                // we have filtered results                addAll((ArrayList<Customer>) results.values);            } else {                // no filter, add entire original list back in                addAll(mCustomers);            }            notifyDataSetChanged();        }    };    public CustomerAdapter(Context context, int textViewResourceId, List<Customer> customers) {        super(context, textViewResourceId, customers);        // copy all the customers into a master list        mCustomers = new ArrayList<Customer>(customers.size());        mCustomers.addAll(customers);        layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        View view = convertView;        if (view == null) {            view = layoutInflater.inflate(R.layout.customerNameLabel, null);        }        Customer customer = getItem(position);        TextView name = (TextView) view.findViewById(R.id.customerNameLabel);        name.setText(customer.getName());        return view;    }    @Override    public Filter getFilter() {        return mFilter;    }}


Instead of overriding getFilter() method in adapter, simply we can override the toString() of the userDefined object (Customer). In toString() just return the field based on what you need to filter. It worked for me.

In my example I'm filtering based on names:

public class Customer{    private int id;    private String name;    @Override    public String toString() {        return this.name;    }}