Search code examples
androidautocompletetextviewandroid-adapter

How to get correct ID of AutoCompleteTextView adapter


I am new to Android development and I ran into a problem which I find difficult to solve. I am trying to figure out how to use an AutoCompleteTextView widget properly. I want to create a AutoCompleteTextView, using XML data from a web service. I managed to get it to work, but I am defenitely not pleased with the output.

I would like to put a HashMap with id => name pairs into the AutoCompleteTextView and get the id of the clicked item. When I click on the autocomplete filtered set output, I want to populate a list underneath the autocompletion box, which I also managed to get to work.

Done so far:

  • autocomplete works well for simple ArrayList, all data filtered correct
  • onItemClick event fires properly after click
  • parent.getItemAtPosition(position) returns correct String representation of the clicked item

The event onItemClick(AdapterView parent, View v, int position, long id) does not behave as I would like. How can I figure out the unfiltered array position of the clicked item? The position of the filtered one is the one I am not interested in.

Further questions:

  • How to handle HashMaps or Collections in AutoCompleteTextView
  • How to get the right itemId in the onItemClick event

I did very extensive research on this issue, but did not find any valuable information which would answer my questions.


Solution

  • The event onItemClick(AdapterView parent, View v, int position, long id) does not behave as I would like.

    This is a normal situation when filtering an adapter. Although the adapter keeps a reference to the initial unfiltered data from its point of view it has a single set of data on which is based(no matter if is the initial one or resulted from a filter operation). But this shouldn't raise any problems. With the default sdk adapters(or with a subclass), in the onItemClick() you get the position for the current list on which the adapter is based. You could then use getItem() to get data item for that position(again it doesn't matter if initial or filtered).

    String data = getItem(position);
    int realPosition = list.indexOf(data); // if you want to know the unfiltered position
    

    this will work for lists and Maps(assuming that you use the SimpleAdapter). And for a Maps you always have the option of adding an additional key to set the unfiltered position in the initial list.

    If you use your own adapter along with an AutoCompleteTextView you could make the onItemClick() give you the right id(the position however you can't change).

    public class SpecialAutoComplete extends AutoCompleteTextView {
    
        public SpecialAutoComplete(Context context) {
            super(context);
        }
    
        @Override
        public void onFilterComplete(int count) {
            // this will be called when the adapter finished the filter
            // operation and it notifies the AutoCompleteTextView
            long[] realIds = new long[count]; // this will hold the real ids from our maps
            for (int i = 0; i < count; i++) {
                final HashMap<String, String> item = (HashMap<String, String>) getAdapter()
                        .getItem(i);
                realIds[i] = Long.valueOf(item.get("id")); // get the ids from the filtered items
            }
            // update the adapter with the real ids so it has the proper data
            ((SimpleAdapterExtension) getAdapter()).setRealIds(realIds);
            super.onFilterComplete(count);
        }
    
    
    }
    

    and the adapter:

    public class SimpleAdapterExtension extends SimpleAdapter {
    
        private List<? extends Map<String, String>> mData;
        private long[] mCurrentIds;
    
        public SimpleAdapterExtension(Context context,
                List<? extends Map<String, String>> data, int resource,
                String[] from, int[] to) {
            super(context, data, resource, from, to);
            mData = data;
        }
    
        @Override
        public long getItemId(int position) {       
            // this will be used to get the id provided to the onItemClick callback
            return mCurrentIds[position];
        }
    
        @Override
        public boolean hasStableIds() {
            return true;
        }
    
        public void setRealIds(long[] realIds) {
            mCurrentIds = realIds;
        }
    
    }
    

    If you also implement the Filter class for the adapter then you could get the ids from there without the need to override the AutoCompleTextView class.