efficient AutoCompleteTextView

258 views Asked by At

The most efficient (in terms of amount of connections) AutoCompleteTextView implementation I found is the DelayAutoCompleteTextView proposed here. However, I think that it can be improved by do not ask for data that you previously asked for. That is, imagine that the AutoCompleteTextView is connected to a web service and retrieves data about a English Dictionary. Then, if the user writes "Egg", the AutoCompleteTextView will ask to the web service for words containing "Egg" like ["Egg", "Egg-head", "Egged", "Egging", "Eggs", ...] and this list is the one will be showed to the user. Nevertheless, if the user refines the query by typing one more letter (i.e., "Eggi"), the AutoCompleteTextView will ask 'again' to the web server for words containing "Eggi" and here is what I think that can be improved. Why do we need to ask to the web service for information we already have? Words containing "Eggi" are included in the ones containing "Egg" so there is no need to ask to the server, instead we must filter the first list we get from the web service.

Does anyone know how to do this?

Thank you!

1

There are 1 answers

0
Fran On

I have a possible solution to this. Maybe it can be improved (could anyone think in a better approach?)

The following code (inspired by this) is an Adapter that implements Filterable. The new part is inside getFilter method where I check if the filter constraint is more restrictive than the previous one. If this is the case I don't want to ask to the webservice since the information is already in the resultList obtained previously by asking the webservice with the previous constrint, which was less restrictive.

public class CityAutoCompleteAdapter extends BaseAdapter implements Filterable {

private static final int MAX_RESULTS = 10;
private Context mContext;
private List<City> resultList = new ArrayList<City>();
private CharSequence previous_constraint = "";

public CityAutoCompleteAdapter(Context context) {
    mContext = context;
}

@Override
public int getCount() {
    return resultList.size();
}

@Override
public City getItem(int index) {
    return resultList.get(index);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.suggestion_list, parent, false);
    }
    TextView tv = (TextView) convertView.findViewById(R.id.text1);
    tv.setText(getItem(position).getNombre() + " (" + getItem(position).getProvincia() + ")");
    tv.setTag(getItem(position).getId_pueblo());
    return convertView;
}

@Override
public Filter getFilter() {
    Filter filter = new Filter() {
        @Override
        protected android.widget.Filter.FilterResults performFiltering(CharSequence constraint) {
            FilterResults filterResults = new FilterResults();
            if (constraint != null) {

                // checking if the new constraint is more general than the previous_constraint one
                int constraints_diff = constraint.toString().compareToIgnoreCase(previous_constraint.toString());

                if (constraints_diff >= 0 && !previous_constraint.equals("")){
                    // the new constraint is more specific than the previous_constraint one
                    List<City> filteredResultList = new ArrayList<City>();

                    // filtering data from resultList instead of retreiving again data from a web service
                    for(City city : resultList){
                        if (city.getName().toLowerCase().startsWith(constraint.toString().toLowerCase())){
                            filteredResultList.add(city);
                        }
                    }
                    // Assign the data to the FilterResults
                    filterResults.values = filteredResultList;
                    filterResults.count = filteredResultList.size();
                }else {
                    // the new constraint is more general than the previous_constraint one
                    // retreiving data from a web service
                    List<City> cities = findCities(mContext, constraint.toString());

                    // Assign the data to the FilterResults
                    filterResults.values = cities;
                    filterResults.count = cities.size();
                }
                previous_constraint = constraint;
            }
            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence constraint, android.widget.Filter.FilterResults results) {
            if (results != null && results.count > 0) {
                resultList = (List<City>) results.values;
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }};
    return filter;
}

/**
 * Returns a search result for the given city name.
 */
private List<City> findCities(Context context, String city_name) {
    WebServiceWrapper wsWrapper = new WebServiceWrapper(context, MAX_RESULTS);
    return wsWrapper.getCities(city_name);
}}

Please if you know how to do this better let me know.