Thursday, October 18, 2012

Android AutoCompleteTextView suggestion list from an external Web Service

Android offers an AutoCompleteTextView widget. If you peer into the source code of the AutoCompleteTextView widget you'll notice that it contains a ListView that renders the suggestion list. This ListView is generally fed by an ArrayAdapter. It's fairly trivial to stick an array like data structure in this ArrayAdapter to display suggestions. This works well for static data. However, if you plan to poll an external Web Service to build your list of suggestions, things get tricky. My first thoughts were to build a custom ListAdapter that would go out to the Web Service on every getView() call. I quickly discarded that idea since it wouldn't mesh well with the ListAdapter/ListView interaction model. I finally settled on using a custom Filter to build the suggestions list from a Web Service. An added advantage of using a custom Filter is that the filter() method is run on its own worker thread. This obviates the need to make the web service call on an AsyncTask. Here's the code:

    private class AutoCompleteAdapter extends ArrayAdapter {
        @Override
        public Filter getFilter() {
            //This is important.
            return new MyFilter();
        }
        
        final class MyFilter extends Filter {
            @Override
            protected FilterResults performFiltering(
                    CharSequence constraint) {
                //This method gets called on a worker thread
                //so no AsyncTasks required here
                FilterResults result = new FilterResults();
                try {
                    URL feedUrl = new URL(...);
                    URLConnection conn = feedUrl.openConnection();
                    InputStream is = conn.getInputStream();
                    //Read from InputStream
                    //Build a List of suggestions
                    result.values = suggestions;
                    result.count = suggestions.size();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } 
                return result;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                clear();
                if (results.count > 0) {
                    for (String s : (List) results.values) {
                        add(s);
                    }
                }
                notifyDataSetChanged();
            }
        }
    }

1 comment:

Unknown said...

Great post!!, thanks!!