开发者

AutoCompleteTextView onItemClick item position or id using HashMap

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.


How to handle HashMaps or Collections in AutoCompleteTextView

You can set your own custom adapter. In your adapter it's up to you where you get your data to a given position.

How to get the right itemId in the onItemClick event

In your custom adapter, you define a filter, and that filter sets the suggested items. You have two different list, one with the original values, and another one with the filtered items. I mean something like this.

private class AutoCompleteItemAdapter extends ArrayAdapter<YourItemClass> implements Filterable {

    private NameFilter      mFilter;
    List<YourItemClass> suggestions;
    List<YourItemClass> mOriginalValues;

    public AutoCompleteItemAdapter(Context context, int resource, List<YourItemClass> suggestions) {
        super(context, resource, suggestions);
        this.suggestions = suggestions;
        this.mOriginalValues = suggestions;
    }

    public void updateData(List<YourItemClass> suggestions) {
               mLock.lock();
               try{
                   this.suggestions = suggestions;
                       this.mOriginalValues = suggestions;
            finally{
                mLock.unlock();
            }
        }

    @Override
    public int getCount() {
        mLock.lock();
        try {
            return suggestions.size();
        } finally {
            mLock.unlock();
        }
    }

    @Override
    public YourItemClass getItem(int position) {
        return mOriginalValues.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // draw your item here...
    }

    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new NameFilter();
        }
        return mFilter;
    }

    private class NameFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();

            if (mOriginalValues == null) {
                mLock.lock();
                try {
                    mOriginalValues = new ArrayList<YourItemClass>(suggestions);
                } finally {
                    mLock.unlock();
                }
            }

            if (prefix == null || prefix.length() == 0) {
                mLock.lock();
                try {
                    ArrayList<YourItemClass> list = new ArrayList<YourItemClass>(mOriginalValues);
                    results.values = list;
                    results.count = list.size();
                } finally {
                    mLock.unlock();
                }
            } else {
                String prefixString = prefix.toString().toLowerCase();

                final List<YourItemClass> values = mOriginalValues;
                final int count = values.size();

                final ArrayList<YourItemClass> newValues = new ArrayList<YourItemClass>(count);

                //              FILTERING
                //
                    // add your hits to the newValues collection
                //
                //
                results.values = newValues;
                results.count = newValues.size();
            }
            return results;
        }


        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            mLock.lock();
            try {
                if (results == null || results.values == null) return; 
                suggestions = new ArrayList<YourItemClass>();
                suggestions = (List<YourItemClass>) results.values;
                if (results.count > 0) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            } finally {
                mLock.unlock();
            }
        }
    }
}

Now this might raise some concurrency issue, as we the reference, the adapter might ask for the size of the list, and a bigger value goes out, which might cause problem in the getView function. (fi.: Attempting to draw 5 element with the underlying data has only 4, because we did another filtering) This the way we used our AutoCompleteTextView, and so far it works great, no problem. I just mentioned that I'm still concerned, and I have this vague feeling that there is a better solution for this.

In your onClick listener, you use the returned value(from the filtered list) as the key in your map, and get the associated value. You can think your list you use an index for the HashMap. After that, you can use your Map to draw your item, or to get your own data.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜