列表视图中的过滤器不是从完整列表中过滤,而是从已过滤的列表中过滤

Filter in listview did not filter from the full list, but from already filtered list

我有一个带过滤器的列表视图。当我在用作过滤器的 edittext 中输入一些单词时,例如 "david",它运行良好,列表中的项目被过滤,它将显示包含 "david" 的所有项目。但是当我删除一些单词时,例如"dav",列表仍然被过滤,但是它是从上次被"david"过滤的过滤出来的。

假设我有 40 件商品,经过 "david" 筛选后,结果变成了 24 件。然后我用 "dav" 再次过滤它,它从“24 项”过滤,而不是“40 项”过滤。

这是我的自定义适配器:

public class WRegistrantListAdapter extends ArrayAdapter<Registrant> {

    private Context mContext;
    private int mResource;
    private List<Registrant> mOriginalList;
    private List<Registrant> mFilteredList;

    public WRegistrantListAdapter(Context context, int resource, ArrayList<Registrant> oobjects, int workshopItemId) {
        super(context, resource, oobjects);
        mContext = context;
        mResource = resource;
        mFilteredList = oobjects;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        //contains code for displaying item.
    }

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

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

                if (mOriginalList == null) {
                    mOriginalList = mFilteredList;
                    Toast.makeText(mContext, String.valueOf(mOriginalList.size()), Toast.LENGTH_SHORT).show();
                }

                if (constraint == null || constraint.isEmpty() || constraint.equals("")) {
                    result.values = mOriginalList;
                    result.count = mOriginalList.size();
                } else {
                    List<Registrant> list = new ArrayList<>();
                    int max = mOriginalList.size();
                    for (int cont = 0; cont < max; cont++) {
                        Registrant item = mOriginalList.get(cont);
                        boolean contains =
                            item.getRegistrantName().toLowerCase().contains(constraint) ||
                                    item.getRegistrantNumber().toLowerCase().contains(constraint);
                        if (contains) {
                            list.add(mOriginalList.get(cont));
                        }
                    }
                    result.values = list;
                    result.count = list.size();
                }

                return result;
            }

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

过滤的哪一部分是错误的?任何帮助将非常感激。希望我的解释不会造成混淆,因为英语不是我的母语。

您应该在适配器中保留两个单独的列表,例如,

private List<Registrant> mOriginalList = new ArrayList();
private List<Registrant> mFilteredList = new ArrayList();

public WRegistrantListAdapter(Context context, int resource, ArrayList<Registrant> oobjects, int workshopItemId) {
    super(context, resource, oobjects);
    mContext = context;
    mResource = resource;
    mFilteredList.addAll(oobjects);
    mOriginalList.addAll(oobjects);
}

最初,它们应该具有相同的值,您将使用 filteredList 来显示您的数据。稍后在过滤器中,您应该像

一样发布您的数据
@Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                filteredList.clear();
                filteredList.addAll((ArrayList<Registrant>) results.values);
                notifyDataSetChanged();
            }

可以在 Filter ListView with arrayadapter

中找到完整的示例

您需要两个不同的列表进行过滤,因此尝试将 mOriginalList = mFilteredList; 更改为 mOriginalList = new ArrayList<>(mFilteredList); 可能会解决问题。

解释:

mOriginalList = mFilteredList; 是具有两个不同名称的相同列表。它在模块化程序中很有用,就像适配器构造函数中的 mFilteredList = oobjects;

mOriginalList = new ArrayList<>(mFilteredList);是对mFilteredList做一个shallow拷贝,存为mOriginalList,所以列表不一样

浅层和深层复制:

示例:如果您的自定义 class、Registrant 包含 public 字段(列表、地图或自定义对象等,则需要 new 用于创建)名为 sample。在浅拷贝下,mOriginalList = new ArrayList<>(mFilteredList);、mOriginalList.get(i) 是 mFilteredList.get(i) 的副本,它们是 2 个不同的 Registrant 对象。但是 mOriginalList.get(i).sample 和 mFilteredList.get(i).sample 是同一个对象。

如果需要mOriginalList.get(i).sample和mFilteredList.get(i).sample是不同的对象,那么就叫深拷贝。制作深拷贝没有现成的方法,你必须根据你的习惯制作你自己的方法class。但是到现在为止,我从来没有一个案例需要深拷贝。

希望对您有所帮助!