我浏览了 ArrayAdapter 的实际源代码,看起来它实际上是按照这种方式编写的。
ArrayAdapter 有两个开头的列表:mObjects 和 mOriginalValues。mObjects 是适配器将使用的主要数据集。以 add() 函数为例:
public void add(T object) {
if (mOriginalValues != null) {
synchronized (mLock) {
mOriginalValues.add(object);
if (mNotifyOnChange) notifyDataSetChanged();
}
} else {
mObjects.add(object);
if (mNotifyOnChange) notifyDataSetChanged();
}
}
mOriginalValues 最初为 null,因此默认情况下所有操作(添加、插入、删除、清除)都针对 mObjects。这一切都很好,直到您决定在列表上启用过滤并实际执行一个。第一次过滤会使用 mObjects 的任何内容初始化 mOriginalValues:
private class ArrayFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (mOriginalValues == null) {
synchronized (mLock) {
mOriginalValues = new ArrayList<T>(mObjects);
//mOriginalValues is no longer null
}
}
if (prefix == null || prefix.length() == 0) {
synchronized (mLock) {
ArrayList<T> list = new ArrayList<T>(mOriginalValues);
results.values = list;
results.count = list.size();
}
} else {
//filtering work happens here and a new filtered set is stored in newValues
results.values = newValues;
results.count = newValues.size();
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
//noinspection unchecked
mObjects = (List<T>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
mOriginalValues 现在拥有原始值/项目的副本,因此适配器可以完成其工作并通过 mObjects 显示过滤列表,而不会丢失预先过滤的数据。
如果我的想法不正确,请原谅我(请告诉并解释),但我觉得这很奇怪,因为现在 mOriginalValues 不再为空,所有对任何适配器操作的后续调用都只会修改 mOriginalValues。然而,由于适配器被设置为将 mObjects 视为其主要数据集,因此它会在屏幕上显示没有发生任何事情。直到您执行另一轮过滤。删除过滤器会触发此操作:
if (prefix == null || prefix.length() == 0) {
synchronized (mLock) {
ArrayList<T> list = new ArrayList<T>(mOriginalValues);
results.values = list;
results.count = list.size();
}
}
mOriginalValues,自从我们的第一个过滤器(尽管我们在屏幕上看不到它发生)以来我们一直在修改它,存储在另一个列表中并复制到 mObjects,最后显示所做的更改。尽管如此,从现在开始就是这样:所有操作都将在 mOriginalValues 上完成,并且只有在过滤后才会出现更改。
至于解决方案,我目前想出的是(1)放置一个布尔标志,告诉适配器操作是否正在进行过滤 - 如果过滤完成,然后复制内容将 mOriginalValues 转换为 mObjects,或者 (2) 简单地调用适配器的 Filter 对象并传递一个空字符串 *.getFilter().filter("") 以在每次操作后强制进行过滤器 [正如 BennySkogberg 所建议的]。
如果有人能对这个问题有更多的了解或确认我刚刚做了什么,我们将不胜感激。谢谢!