简体   繁体   中英

How can I speed up an AutocompleteTextView in Android?

Hi everyone I have an adapter which extends the ArrayAdapter class and overrides some Filterable methods. I am using this Adapter to perform some filtering while the user types inside an AutocompleteTextView. But I saw that if you type a bit fast the updanting of 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 someone knows how to increase the performance of this kind of AutocompleteTextView and make the updating a faster. What should I do? Thanks!

EDIT: I have createed this classes: Vertex: public class Vertex {

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 get a null pointer warning when I type in the AutoCompleteTextView at this line:

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

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

You should look into using a trie , it would be perfect for auto complete.

Here is what one looks like:

在此处输入图片说明

As you get more characters, you can traverse further down the tree, and the number of possible options will get smaller and smaller.

This would be significantly faster than looking over your entire list each time.


Edit: After reflecting on my answer I think a much easier solution would be to just use any kind of sorted map. Checkout this answer for an example .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM