0

I have an Android Application, and there's a part where the user can use an AutoCompleteTextView to select names. The user can select a name and then details (such as address) would appear in the next activity. What I do is that when the user selects a name, I get that name's position from the ArrayList, and go to my Address ArrayList, get the address at the same position, and then I have my data.

However, some of the names tend to repeat, for example, I have a Name ArrayList as such:

[A, B, B, C]

and an Address ArrayList as such:

[Address A, Address B, Address C, Address D]

when the user clicks the 2nd B in the AutoCompleteTextView, the position returned will be that of the first B, NOT the second B, and therefore, it will give the Address B instead of Address C.

I've looked around and I've tried to make my custom ArrayAdapter for my AutoCompleteTextView to display my custom class with the Name and the Address. However, I did not have much luck with that.

The next thing I looked into was to using a HashMap<String, String> as shown in thisStackOverflow Question. It is very similar to what is used for a Custom ListView, only that it has a getFilter function. I have tried to adapt that code as such:

public class actvMapFilter extends 
    ArrayAdapter<Map<String, String>> implements Filterable {
    private Context mContext;
    private List<Map<String, String>> mClientList;
    private List<Map<String, String>> mMutableList;

    public actvMapFilter(Context context, 
               List<Map<String, String>> objects) {
        super(context, android.R.layout.simple_list_item_1, objects);
        mContext = context;
        mClientList = objects;
        // TODO Auto-generated constructor stub
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;

        if (v == null) {
            LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(android.R.layout.simple_dropdown_item_1line, null);
        }

        TextView nameView = (TextView) v.findViewById(android.R.id.text1);

        if(position < mClientList.size()){
            Map<String, String> clientMap = mClientList.get(position);
            nameView.setText(clientMap.keySet().toArray()[position].toString());
        }

        return v;
    }


    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected void publishResults(CharSequence constraint,
                                          FilterResults results) {

                if (results.count > 0) {
                    mClientList = (ArrayList<Map<String, String>>) results.values;
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();

                ArrayList<Map<String, String>> result = new ArrayList<Map<String, String>>();
                HashMap<String,String> myMap = new HashMap<String,String>();

                if(constraint != null && mClientList!=null){

                    int length = mClientList.size();
                    int i = 0;

                    Log.e("","constraint = " + constraint.toString().toUpperCase());
                    Log.e("","constraint and list not null.");
                    Log.e("","length of original list = " + length);

                    while(i < length){

                        String key = mClientList.get(i).keySet().toArray()[0].toString();
                        String value = mClientList.get(i).values().toArray()[0].toString();

                        if(key.contains(constraint.toString().toUpperCase())){
                            myMap.put(key, value);
                            result.add(myMap);
                        }

                        i++;

                    }

                    Log.e("","filter results = " + myMap);
                    Log.e("","filter results count = " + myMap.size());

                    filterResults.values = result;
                    filterResults.count = result.size();
                }
                FilterResults r = new FilterResults();

                r.values = result;
                r.count = result.size();

                return r;
            }
        };
    }
}

It is very similar to what was marked as the answer. However, what I do in my getFilter function is that when I have a constraint given, I check if the key part contains the constraints, I add those.

This works well, I am told by my LogCat that if I type a certain character, my resulting HashMap would contain the entries with the constrains only.

However, what happens is that when I type in a 2nd succeeding character, the filter does not seem to work any more. I am given a blank filtered result HashMap and the dropdown menu reflects the blank result because I don't have any suggestive text any more.

How can I implement a Filterable ArrayAdapter properly?

halfer
  • 19,824
  • 17
  • 99
  • 186
Razgriz
  • 7,179
  • 17
  • 78
  • 150
  • why do you need custom Filter at all? ArrayAdapter is Filterable after all... – pskink Aug 01 '15 at 11:34
  • @pskink I know it is, however, I'm not sure an ArrayAdapter can use a HashMap? What I want to do is when a user clicks a name, I'll be able to accurately get the corresponding Address and I won't be achieve that using an ArrayList of Strings when I have repeating Names. And without a customer Filter, I don't think I'll be able to make the AutocompleteTextView work? Am I getting this situation all jumbled up? – Razgriz Aug 01 '15 at 11:56
  • then use ArrayAdapter, also override toString in YourClassHavingNameAndAddress – pskink Aug 01 '15 at 12:07
  • but honestly if i were you i would follow that: http://stackoverflow.com/a/19860624/2252830 and just implement `runQuery` method – pskink Aug 01 '15 at 12:12
  • I might go with overriding the toString method. Thank you for the ideas! On a side note, would I be able to use an ordinary ArrayAdapter on a custom object or should I use my existing ArrayAdpaters that used my custom object before? – Razgriz Aug 01 '15 at 12:25
  • but still with custom `toString` you dont have the full control of what is filtered out, with `FilterQueryProvider` you do have the full control – pskink Aug 01 '15 at 12:29
  • Alright, I will look into that. – Razgriz Aug 01 '15 at 12:32

0 Answers0