我使用自定义ArrayAdapter类在ListView中显示一些数据。我在Action Bar中有一个微调器,根据它的项目选择我想过滤数据并在列表视图中重新填充它。
目前,当我的活动加载时,数据显示正确,但是当我从微调器中选择任何项目时,ListView变空并且不显示任何数据,尽管操作栏仍然出现。
你能告诉我我做错了什么吗?
这是我的自定义ArrayAdapter类:
public class MyAdapter extends ArrayAdapter implements Filterable {
private ArrayList < ArrayList < String >> arrayList;
private LayoutInflater theInflater;
public MyAdapter(Context context, ArrayList arrayList) {
super(context, R.layout.row_layout, arrayList);
this.arrayList = arrayList;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
theInflater = LayoutInflater.from(getContext());
View theView = theInflater.inflate(R.layout.row_layout, parent, false);
ArrayList < String > values = (ArrayList < String > ) getItem(position);
TextView a= (TextView) theView.findViewById(R.id.a);
TextView b= (TextView) theView.findViewById(R.id.b);
TextView c= (TextView) theView.findViewById(R.id.c);
a.setText(values.get(0));
b.setText(values.get(1));
c.setText(values.get(2));
return theView;
}
public Filter geFilter() {
Filter filter = new Filter() {@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
ArrayList al = new ArrayList();
al.add("ValueA1");
al.add("ValueA2");
al.add("ValueA3");
ArrayList bl = new ArrayList();
bl.add("ValueB1");
bl.add("ValueB2");
bl.add("ValueB3");
ArrayList < ArrayList < String >> array = new ArrayList < > ();
array.add(al);
array.add(bl);
results.count = array.size();
results.values = array;
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
arrayList = (ArrayList) results.values;
notifyDataSetChanged();
}
};
return filter;
}
}
在Spinner的项目选择的监听器中,我有:
theAdapter.getFilter().filter("Incoming");
答案 0 :(得分:1)
不幸的是,你的适配器出现了很多问题。例如没有实施ViewHolder paradigm。请注意,这不是您遇到问题的原因。但它确实解决了您的解决方案将产生的性能问题。
过滤本身不起作用,因为ArrayAdapter
跟踪它自己的内部数据列表。 ArrayAdapter
不保证您在外部跟踪的列表是相同的。在过滤操作期间尤其如此。您可以详细了解跟踪外部列表的危险,例如here。
您的Filter
非常有问题。
arrayList
不再与内部ArrayAdapter
正在跟踪的ArrayList
相同。这会在您改变适配器时导致问题。performFiltering()
,以便在过滤开始之前跟踪原始数据。否则,无法恢复过滤掉的数据。arrayList
发生在后台线程上。虽然您在此方法期间似乎不访问ArrayAdapter
(这是实际过滤数据的唯一方法),但您需要确保所有列表修改都已同步。 arrayList
本身已处理同步,但无法将外部publishResults()
与其同步。这意味着您无法在不冒并发修改错误的情况下编写过滤器。results.count == 0
时notifyDataSetInvalidated()
,您必须results.count > 0
。如果notifyDataSetChanged()
,您必须ArrayAdapter
。Filterable
已实施ArrayAdapter
。将其添加到自定义适配器是多余的。 ArrayAdapter
拥有可过滤的实现存在一些错误。这里是a piece,它讨论了问题以及如何解决它。相关性是它讨论了如何创建自己的可过滤逻辑来解决问题。简而言之,您无法使用BaseAdapter
创建自己的自定义过滤器。您需要使用data = {"name": "chan", "age", "35"};
从头开始创建自己的适配器。
或者,您可以使用third party library,它提供了一种非常简单的方法来实现您自己的自定义过滤逻辑。我强烈建议你去看那个人。另外,我强烈建议您更多地了解Google如何正确创建自定义适配器。他们有很多东西,你需要学习很多东西,从头开始正确实施。
答案 1 :(得分:0)
在publishResults()
方法中执行以下操作:
清除列表,再次添加结果数据并再次调用notifyDataSetInvalidated()
。
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
arrayList = (ArrayList) results.values;
notifyDataSetChanged();
clear();
for(int i = 0, l = arrayList.size(); i < l; i++) {
add(arrayList.get(i));
}
notifyDataSetInvalidated();
}