How to speed up AutocompleteTextView in Android?

Hi everyone, I have an adapter that extends the ArrayAdapter class and overrides some Filterable methods. I am using this adapter to do some filtering when the user types inside the AutocompleteTextView. But I have seen that if you type a bit quickly, updating the filtered items becomes very slow. This is the adapter class:

public class MunicipalitySearchAdapter extends ArrayAdapter<Municipality> {

private ArrayList<Municipality> municipalities;
private ArrayList<Municipality> allMunicipalities;
private ArrayList<Municipality> suggestedMunicipalities;
private int viewResourceId;

@SuppressWarnings("unchecked")
public MunicipalitySearchAdapter(Context context, int viewResourceId, ArrayList<Municipality> municipalities) {
    super(context, viewResourceId, municipalities);
    this.municipalities = municipalities;
    this.allMunicipalities = (ArrayList<Municipality>) this.municipalities.clone();
    this.suggestedMunicipalities = new ArrayList<Municipality>();
    this.viewResourceId = viewResourceId;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = inflater.inflate(this.viewResourceId, null);
    }
    Municipality municipality = municipalities.get(position);
    if (municipality != null) {
        TextView munNameTxtView = (TextView) v.findViewById(R.id.name);
        TextView proSignTxtView = (TextView) v.findViewById(R.id.sign);
        if (munNameTxtView != null) {
            munNameTxtView.setText(municipality.getName());
        }
        if (proSignTxtView != null) {
            proSignTxtView.setText(municipality.getProvinceSign());
        }
 }
    return v;
}


@Override 
public Filter getFilter() {
    return municipalityFilter;
}

Filter municipalityFilter = new Filter() {

    @Override
    public String convertResultToString(Object resultValue) {
        String str = ((Municipality) (resultValue)).getName();
        return str;
    }

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        if (constraint != null) {
            suggestedMunicipalities.clear();
            for (Municipality municipality : allMunicipalities) {
                if (municipality.getName().toLowerCase(Locale.getDefault()).startsWith(constraint.toString().toLowerCase(Locale.getDefault()))) {
                    suggestedMunicipalities.add(municipality);
                }
            }
            FilterResults filterRes = new FilterResults();
            filterRes.values = suggestedMunicipalities;
            filterRes.count = suggestedMunicipalities.size();
            return filterRes;
        }
        else {
            return new FilterResults();
        }
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        if (results != null && results.count > 0) {
            @SuppressWarnings("unchecked")
            ArrayList<Municipality> filteredMunicipalities = (ArrayList<Municipality>) results.values;
            ArrayList<Municipality> supportMunicipalitiesList = new ArrayList<Municipality>();

            clear();
            for (Municipality mun : filteredMunicipalities) {
                supportMunicipalitiesList.add(mun);
            }
            Iterator<Municipality> municipalityIterator = supportMunicipalitiesList.iterator();
            while (municipalityIterator.hasNext()) {
                Municipality municipality = municipalityIterator.next();
                add(municipality);
            }
            notifyDataSetChanged();
        }           
    }
};
 }

      

I would like to ask if anyone knows how to increase the performance of this type of AutocompleteTextView and make the update faster. What should I do? Thank!

EDIT: I created these classes: Vertex: public Vertex class {

private HashMap<Character, Vertex> vertexSons;
private List<Integer> wordsIndexList;
private List<Integer> prefixesIndexList;
private int wordsNumber;
private int prefixesNumber;

public Vertex() {
    vertexSons = new HashMap<Character, Vertex>();
    wordsIndexList = new ArrayList<Integer>();
    prefixesIndexList = new ArrayList<Integer>();
    wordsNumber = 0;
    prefixesNumber = 0;
}

public boolean hasWords() {
    if (wordsNumber > 0) {
        return true;
    }
    return false;
}

public boolean hasPrefixes() {
    if (prefixesNumber > 0) {
        return true;
    }
    return false;
}

public void addVertexSon(Character character) {
    vertexSons.put(character, new Vertex());
}

public void addIndexToWordsIndexList(int index) {
    wordsIndexList.add(index);
}

public void addIndexToPrefixesIndexList(int index) {
    prefixesIndexList.add(index);
}

public HashMap<Character, Vertex> getVertexSons() {
    return vertexSons;
}

public List<Integer> getWordsIndexList() {
    return wordsIndexList;
}

public List<Integer> getPrefixesIndexList() {
    return prefixesIndexList;
}

public int getWordsNumber() {
    return wordsNumber;
}

public int getPrefixesNumber() {
    return prefixesNumber;
}

public void increaseWordsNumber() {
    wordsNumber++;
}

public void increasePrefixesNumber() {
    prefixesNumber++;
}
}

      

And Trie:

public class Trie {

private Vertex rootVertex;

public Trie(List<Trieable> objectList, Locale locale) {
    rootVertex = new Vertex();

    for (int i = 0; i<objectList.size(); i++) {
        String word = objectList.get(i).toString().toLowerCase(locale);
        addWord(rootVertex, word, i);
    }
}

public Vertex getRootVertex() {
    return rootVertex;
}

public void addWord(Vertex vertex, String word, int index) {
    if (word.isEmpty()) { 
        vertex.addIndexToWordsIndexList(index);
        vertex.increaseWordsNumber();
    }
    else {
        vertex.addIndexToPrefixesIndexList(index);
        vertex.increasePrefixesNumber();
        Character fChar = word.charAt(0);
        HashMap<Character, Vertex> vertexSons = vertex.getVertexSons();

        if (!vertexSons.containsKey(fChar)) {
            vertex.addVertexSon(fChar);
        }

        word = (word.length() == 1) ? "" : word.substring(1);
        addWord(vertexSons.get(fChar), word, index);
    }
}

public List<Integer> getWordsIndexes(Vertex vertex, String word) {
    if (word.isEmpty()) {
        return vertex.getWordsIndexList();
    }
    else {
        Character fChar = word.charAt(0);
        if (!(vertex.getVertexSons().containsKey(fChar))) {
            return null;
        }
        else {
            word = (word.length() == 1) ? "" : word.substring(1);
            return getWordsIndexes(vertex.getVertexSons().get(fChar), word);
        }
    }
}

public List<Integer> getPrefixesIndexes(Vertex vertex, String prefix) {
    if (prefix.isEmpty()) {
        return vertex.getWordsIndexList();
    }
    else {
        Character fChar = prefix.charAt(0);
        if (!(vertex.getVertexSons().containsKey(fChar))) {
            return null;
        }
        else {
            prefix = (prefix.length() == 1) ? "" : prefix.substring(1);
            return getWordsIndexes(vertex.getVertexSons().get(fChar), prefix);
        }
    }
}

}

      

And edited my filter like this:

Filter municipalityFilter = new Filter() {



    @Override
    public String convertResultToString(Object resultValue) {
        String str = ((Municipality) (resultValue)).getName();
        return str;
    }

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {

        if (constraint != null) {
            String constraintString = constraint.toString().trim();
            suggestedMunicipalities.clear();

            List<Integer> wordsIndexesList = municipalityTrie.getWordsIndexes(municipalityTrie.getRootVertex(), constraintString);
            for (int index : wordsIndexesList) {
                suggestedMunicipalities.add(allMunicipalities.get(index));
            }

            List<Integer> prefixesIndexesList = municipalityTrie.getPrefixesIndexes(municipalityTrie.getRootVertex(), constraintString);
            for (int index : prefixesIndexesList) {
                suggestedMunicipalities.add(allMunicipalities.get(index));
            }

            FilterResults filterRes = new FilterResults();
            filterRes.values = suggestedMunicipalities;
            filterRes.count = suggestedMunicipalities.size();
            return filterRes;
        }
        else {
            return new FilterResults();
        }
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        if (results != null && results.count > 0) {
            @SuppressWarnings("unchecked")
            ArrayList<Municipality> filteredMunicipalities = (ArrayList<Municipality>) results.values;
            ArrayList<Municipality> supportMunicipalitiesList = new ArrayList<Municipality>();

            clear();
            for (Municipality mun : filteredMunicipalities) {
                supportMunicipalitiesList.add(mun);
            }
            Iterator<Municipality> municipalityIterator = supportMunicipalitiesList.iterator();
            while (municipalityIterator.hasNext()) {
                Municipality municipality = municipalityIterator.next();
                add(municipality);
            }
            notifyDataSetChanged();
        }           
    }
};

      

Now I am getting a null pointer warning when typing into AutoCompleteTextView on this line:

List<Integer> wordsIndexesList = municipalityTrie.getWordsIndexes(municipalityTrie.getRootVertex(), constraintString);
            for (int index : wordsIndexesList) {
                suggestedMunicipalities.add(allMunicipalities.get(index));
            }

      

In the for statement (int index: wordsIndexesList) . What should I do? Thank!

+2


source to share


1 answer


You should learn the trie , that would be ideal for auto completion.

This is what it looks like:

enter image description here

As you get more characters, you can move further up the tree, and the number of possible options will become less and less.



This will be significantly faster than going through your entire list every time.


Edit: After thinking about my answer, I think it's much easier to decide to use any sorted map. Check this answer for an example .

+4


source







All Articles