Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 626
sarath Avatar asked Jul 17 '12 12:07

sarath


2 Answers

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.

like image 52
user Avatar answered Oct 16 '22 15:10

user


Using the Luksprog approach, I made some similar with ArrayAdapter.

    public class SimpleAutoCompleteAdapter extends ArrayAdapter<String>{
        private String[] mData;
        private int[] mCurrentIds;

        public SimpleAutoCompleteAdapter(Context context, int textViewResourceId,
             String[] objects) {
             super(context, textViewResourceId, objects);
             mData=objects;
        }

        @Override
        public long getItemId(int position) {
            String data = getItem(position);
            int index = Arrays.asList(mData).indexOf(data);
            /*
             * Atention , if your list has more that one same String , you have to improve here  
             */
            // this will be used to get the id provided to the onItemClick callback
            if (index>0)
                return (long)mCurrentIds[index];
            else return 0;
        }

        @Override
        public boolean hasStableIds() {
            return true;
        }

        public void setRealIds(int[] realIds) {
            mCurrentIds = realIds;
        }

    }
like image 45
Felipe FMMobile Avatar answered Oct 16 '22 13:10

Felipe FMMobile