自定义 ListView ArrayAdapter 不显示过滤后的数据
Custom ListView ArrayAdapter not displaying filtered data
我正在使用自定义 ArrayAdapter class 在 ListView 中显示一些数据。我在 Action Bar 中有一个微调器,基于它的项目 selection,我想过滤数据并在列表视图中重新填充它。
目前,当我的 activity 加载数据时,数据显示正确,但是当我 select 来自微调器的任何项目时,ListView 变空并且不显示任何数据,尽管 Actionbar 仍然出现.
你能告诉我我做错了什么吗?
这是我自定义的 ArrayAdapter Class :
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 的项目 selected listener 中,我有:
theAdapter.getFilter().filter("Incoming");
在 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();
}
不幸的是,您在适配器方面做错了很多事。比如不执行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
自己的可过滤实现存在一些错误。这里的 a piece 讨论了这个问题以及如何解决它。相关性在于它讨论了如何创建您自己的可过滤逻辑来解决问题。简而言之,您不能使用 ArrayAdapter
创建自己的自定义过滤器。您需要使用 BaseAdapter
从头开始创建自己的适配器。
或者,您可以使用 third party library,它提供了一种非常简单的方法来实现您自己的自定义过滤逻辑。我强烈建议改为看看那个人。此外,我强烈建议您 Google 了解更多有关如何正确创建自定义适配器的信息。他们有很多东西,你需要学习很多东西才能从头开始正确实施。
我正在使用自定义 ArrayAdapter class 在 ListView 中显示一些数据。我在 Action Bar 中有一个微调器,基于它的项目 selection,我想过滤数据并在列表视图中重新填充它。
目前,当我的 activity 加载数据时,数据显示正确,但是当我 select 来自微调器的任何项目时,ListView 变空并且不显示任何数据,尽管 Actionbar 仍然出现.
你能告诉我我做错了什么吗?
这是我自定义的 ArrayAdapter Class :
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 的项目 selected listener 中,我有:
theAdapter.getFilter().filter("Incoming");
在 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();
}
不幸的是,您在适配器方面做错了很多事。比如不执行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
自己的可过滤实现存在一些错误。这里的 a piece 讨论了这个问题以及如何解决它。相关性在于它讨论了如何创建您自己的可过滤逻辑来解决问题。简而言之,您不能使用 ArrayAdapter
创建自己的自定义过滤器。您需要使用 BaseAdapter
从头开始创建自己的适配器。
或者,您可以使用 third party library,它提供了一种非常简单的方法来实现您自己的自定义过滤逻辑。我强烈建议改为看看那个人。此外,我强烈建议您 Google 了解更多有关如何正确创建自定义适配器的信息。他们有很多东西,你需要学习很多东西才能从头开始正确实施。