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;
    }
}

In the above code publisHResults() method gives the concurrent modification exception.... we have to modify the code as:

@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
    ArrayList<Customer> filteredList = (ArrayList<Customer>) results.values;
    ArrayList<Customer> customerList=new ArrayList<Customer>();
    if (results != null && results.count > 0) {
        clear();
        for (Customer c : filteredList) {
            customerList.add(c);
        }
        Iterator<Customer> customerIterator=getResult.iterator();
        while (customerIterator.hasNext()) {
            Customer customerIterator=customerIterator.next();
            add(customerIterator);
        }
        notifyDataSetChanged();
    }
}