使用 ArrayAdapter<T implements Parcelable> 上的过滤器过滤具有多个 TextView 的自定义 ListView

Filtering custom ListView with multiple TextViews using a Filter on an ArrayAdapter<T implements Parcelable>

我有一个 class class CustomAdapter extends ArrayAdapter<CustomListItem>,其中 CustomListItem implements Parcelable,并且有 3 个字符串变量 (String a, b, c;)

加载 ListView 时一切正常。但是,现在我想使用我的 SearchView 仅显示包含用户输入的文本的列表元素。我希望 CustomAdapter 的过滤器查看该文本的 a、b 和 c,并显示包含该文本的任何列表项。

因此,例如,如果用户键入 "ar",而 a b c 是 "Rome", "Male", "Arnold",无论哪个内容在哪个变量中,因为其中一个有 "Ar"(我不希望它区分大小写)我希望该项目显示在列表中。

目前,这个过滤器业务看起来让我很困惑,在 Whosebug 中似乎有很多自定义过滤器的答案,但我找不到具有我所描述的那种行为的答案。到目前为止,这就是我所拥有的:

public class CustomAdapter extends ArrayAdapter<CustomListItem> {

    public CustomAdapter(Context context, int textViewResourceId) {
        super(context, textViewResourceId);
    }

    public CustomAdapter(Context context, int resource, List<CustomListItem> items) {
        super(context, resource, items);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View v = convertView;

        if (v == null) {
            LayoutInflater vi;
            vi = LayoutInflater.from(getContext());
            v = vi.inflate(R.layout.row_layout, null);
        }

        CustomListItem s = getItem(position);

        if (s != null) {
            TextView a = (TextView) v.findViewById(R.id.a);
            TextView b = (TextView) v.findViewById(R.id.b);
            TextView c = (TextView) v.findViewById(R.id.c);

            if (a != null) {
                a.setText(s.getA());
            }

            if (b != null) {
                b.setText(s.getB());
            }

            if (c != null) {
                c.setText(s.getC());
            }
        }
        return v;
    }

    @Override
    public Filter getFilter() {
        return new Filter() {

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults result = new FilterResults();

                List<CustomListItem> list = new ArrayList<>();
                int max = getCount();
                for (int cont = 0; cont < max; cont++) {
                    if (constraint != null) {
                        CustomListItem item = getItem(cont);
                        boolean contains =
                                item.getA().toLowerCase().contains(constraint) ||
                                item.getB().toLowerCase().contains(constraint) ||
                                item.getC().toLowerCase().contains(constraint);
                        if (contains) {
                            list.add(getItem(cont));
                        }
                    } else {
                        list.add(getItem(cont));
                    }
                }

                result.values = list;
                result.count = list.size();

                return result;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                if (results.count > 0) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }
        };
    }
}

但这行不通,可能是因为我不知道自己在做什么。这是 CustomListItem:

public class CustomListItem implements Parcelable {
    private String a, b, c;

    public CustomListItem(String a, String b, String c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    private CustomListItem(Parcel in) {
        a = in.readString();
        b = in.readString();
        c = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(a);
        dest.writeString(b);
        dest.writeString(c);
    }

    public String getA() {
        return a;
    }

    public String getB() {
        return b;
    }

    public String getC() {
        return c;
    }

    @Override
    public int describeContents(){
        return 0;
    }

    public static final Parcelable.Creator<CustomListItem> CREATOR
            = new Parcelable.Creator<CustomListItem>() {
        public CustomListItem createFromParcel(Parcel in) {
            return new CustomListItem(in);
        }

        public CustomListItem[] newArray(int size) {
            return new CustomListItem[size];
        }
    };
}

然后我在 AppCompatActivity 上添加了这样的过滤器 class:

SearchView searchView = (SearchView) findViewById(R.id.searchView);
final CustomAdapter adapter = new CustomAdapter(getApplicationContext(), R.layout.row_layout, item_list); //item_list is my list of custom items, defined elsewhere

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String text) {
        adapter.getFilter().filter(text);
        return true;
    }
    @Override
    public boolean onQueryTextChange(String text) {
        adapter.getFilter().filter(text);
        return true;
    }
});

我认为我的代码唯一的错误是 getFilter() 方法,所以我正在寻找的答案是实现我刚才所说的正确和干净的方法。我也很乐意解释我做错了什么,以及一些例子。感谢您的宝贵时间!

解决方案: 根据 Submersed 的回答,我进行了必要的更改以使代码正常工作。正如预期的那样,问题仅限于过滤器。但是,由于我更改了 CustomAdapter class 中的其他内容以实现我的解决方案,因此这里是整个固定的 class:

public class CustomAdapter extends ArrayAdapter<CustomListItem> {

    private final List<CustomListItem> mList;

    public CustomAdapter(Context context, int resource, List<CustomListItem> items) {
        super(context, resource, items);
        mList = new ArrayList<>(items);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View v = convertView;

        if (v == null) {
            LayoutInflater vi;
            vi = LayoutInflater.from(getContext());
            v = vi.inflate(R.layout.row_layout, null);
        }

        CustomListItem s = getItem(position);

        if (s != null) {
            TextView a = (TextView) v.findViewById(R.id.a);
            TextView b = (TextView) v.findViewById(R.id.b);
            TextView c = (TextView) v.findViewById(R.id.c);

            if (a != null) {
                a.setText(s.getA());
            }

            if (b != null) {
                b.setText(s.getB());
            }

            if (c != null) {
                c.setText(s.getC());
            }
        }
        return v;
    }

    @Override
    public Filter getFilter() {
        return new Filter() {

            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {
                FilterResults result = new FilterResults();
                String constraint = charSequence.toString().toLowerCase();

                if (constraint == null || constraint.isEmpty()) {
                    result.values = mList;
                    result.count = mList.size();
                } else {
                    List<CustomListItem> list = new ArrayList<>();
                    int max = mList.size();
                    for (int cont = 0; cont < max; cont++) {
                        CustomListItem item = mList.get(cont);
                        boolean contains =
                                item.getA().toLowerCase().contains(constraint) ||
                                item.getB().toLowerCase().contains(constraint) ||
                                item.getC().toLowerCase().contains(constraint);
                        if (contains) {
                            list.add(mList.get(cont));
                        }
                    }
                    result.values = list;
                    result.count = list.size();
                }

                return result;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                clear();
                addAll((ArrayList<CustomListItem>) results.values);
                notifyDataSetChanged();
            }
        };
    }
}

在您的 publishResults 方法中:

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }

您没有将适配器上的筛选结果设置为要在使数据集无效之前显示的新数据集。此外,您还应该保留原始值的副本,因此如果它们清空了查询,您可以保留并重置原始结果。

为框架示例代码编辑: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/widget/ArrayAdapter.java#ArrayAdapter.ArrayFilter