自定义 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问题很大

  1. 它将您的外部数据列表重新分配给一个新列表,这意味着您的 arrayList 不再是内部 ArrayAdapter 跟踪的那个列表。这将在稍后改变适配器时导致问题。
  2. 就目前而言,您的实施似乎并未实际过滤任何内容。通常您还会有第二个 ArrayList 以便在过滤开始之前跟踪原始数据。否则无法恢复被过滤掉的数据。
  3. performFiltering() 发生在后台线程上。虽然在此方法期间您似乎没有访问 arrayList(这将是实际过滤数据的唯一方法),但您需要确保同步所有列表修改。 ArrayAdapter 本身已经处理同步,但无法将外部 arrayList 与其同步。这意味着您实际上无法在不冒并发修改错误的情况下编写过滤器。
  4. publishResults()results.count == 0,你必须notifyDataSetInvalidated()。如果 results.count > 0,则必须 notifyDataSetChanged().
  5. ArrayAdapter 已经实施 Filterable。将其添加到您的自定义适配器是多余的。

ArrayAdapter 自己的可过滤实现存在一些错误。这里的 a piece 讨论了这个问题以及如何解决它。相关性在于它讨论了如何创建您自己的可过滤逻辑来解决问题。简而言之,您不能使用 ArrayAdapter 创建自己的自定义过滤器。您需要使用 BaseAdapter 从头开始​​创建自己的适配器。

或者,您可以使用 third party library,它提供了一种非常简单的方法来实现您自己的自定义过滤逻辑。我强烈建议改为看看那个人。此外,我强烈建议您 Google 了解更多有关如何正确创建自定义适配器的信息。他们有很多东西,你需要学习很多东西才能从头开始正确实施。