【发布时间】:2014-09-23 08:29:12
【问题描述】:
我有一个带有自定义 ArrayAdapter 的 AutoCompleteTextView,它使用 ArrayList<Product>。
我得出的结论是 AutoCompleteTextView 的自定义 ArrayAdapter 必须 implements Filterable 并且您必须进行自己的过滤。
从this SO-question & accepted answer 和this example,我制作了以下ArrayAdapter:
public class AutoCompleteAdapter extends ArrayAdapter<Product> implements Filterable
{
// Logcat tag
private static final String TAG = "AutoCompleteAdapter";
// The OrderedProductItem we need to get the Filtered ProductNames
OrderedProductItem orderedProductItem;
private Context context;
private ArrayList<Product> productsShown, productsAll;
// Default Constructor for an ArrayAdapter
public AutoCompleteAdapter(Context c, int layoutId, ArrayList<Product> objects, OrderedProductItem opi){
// Though we don't use the Layout-ResourceID , we still need it for the super
super(c, layoutId, objects);
L.Log(TAG, "AutoCompleteAdapter Constructor", LogType.VERBOSE);
// ArrayAdapter's setNotifyOnChange is true by default,
// but I set it nonetheless, just in case
setNotifyOnChange(true);
context = c;
replaceList(objects, true);
orderedProductItem = opi;
}
// Setup the ListItem's UI-elements
@Override
public View getView(int position, View convertView, ViewGroup parent){
return createTextViewAsItem(position);
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent){
return createTextViewAsItem(position);
}
// To prevent repetition, we have this private method
private TextView createTextViewAsItem(int position){
TextView label = new TextView(context);
String name = "";
if(productsShown != null && productsShown.size() > 0 && position >= 0 && position < productsShown.size() - 1)
name = productsShown.get(position).getName();
label.setText(name);
return label;
}
// Replace the List
// When the boolean is set, we replace this ArrayAdapter's List entirely,
// instead of just the filtering
@SuppressWarnings("unchecked")
public void replaceList(ArrayList<Product> p, boolean replaceInitialList){
if(p != null && p.size() > 0){
productsShown = p;
if(replaceInitialList)
productsAll = (ArrayList<Product>)productsShown.clone();
notifyDataSetChanged();
}
}
// Since we are using an AutoCompleteTextView, the Filtering has been reset and we need to apply this ourselves..
Filter filter = new Filter(){
@Override
public String convertResultToString(Object resultValue){
return ((Product)resultValue).getName();
}
@Override
protected FilterResults performFiltering(CharSequence constraint){
FilterResults filterResults = new FilterResults();
if(productsAll != null){
// If no constraint is given, return the whole list
if(constraint == null){
filterResults.values = productsAll;
filterResults.count = productsAll.size();
}
else if(V.notNull(constraint.toString(), true)){
L.Log(TAG, "performFiltering: " + constraint.toString(), LogType.VERBOSE);
ArrayList<Product> suggestions = new ArrayList<Product>();
if(p.size() > 0)
for(Product p : productsAll)
if(p.getName().toLowerCase(Locale.ENGLISH).contains(constraint.toString().toLowerCase(Locale.ENGLISH)))
suggestions.add(p);
filterResults.values = suggestions;
filterResults.count = suggestions.size();
}
}
return filterResults;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if(results != null && results.count > 0)
replaceList((ArrayList<Product>)results.values, false);
}
};
@Override
public Filter getFilter(){
return filter;
}
}
一切都很完美。但是,由于我有一个大约 1250 个产品的列表,并且每次用户更改他在 AutoCompleteTextView 中的输入时,这些产品都会循环,包括创建两个新实例(FilterResults 和 ArrayList),我想知道是否有更好的解决方案这无需循环每次用户输入更改的所有内容。
如果没有,我就保留这个。我只是想知道,因为使用包含大约 1250 个对象的 AutoCompleteTextView、自定义 ArrayAdapter(包括自定义过滤)和自定义 TextWatcher,它对性能来说并不是那么好。特别是因为这个 AutoCompleteTextView 是在 ListView 的项目内使用的。这意味着我对每个项目都有一个 AutoCompleteTextView(可能范围从 ~ 5 到 50,平均约为 15)。
【问题讨论】:
标签: android performance autocomplete android-arrayadapter autocompletetextview