jhi*_*hie 14 android listview filtering filter android-arrayadapter
我有一个ListView(带有setTextFilterEnabled(true))和一个自定义适配器(扩展ArrayAdapter),每当添加/插入新项目时,我都会从主UI线程更新.一切都工作正常 - 新项目立即显示在列表中.但是,当我尝试过滤列表时,这就停止了.
过滤工作,但我做了一次,我所有成功修改列表内容(添加,删除)的尝试都不再显示.我使用Log来查看适配器的列表数据是否得到了正确的更新,但确实如此,但它不再与显示的ListView同步.
是什么导致了这个以及如何最好地解决这个问题?
jhi*_*hie 16
我浏览了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();
}
}
Run Code Online (Sandbox Code Playgroud)
mOriginalValues最初为null,因此默认情况下,所有操作(add,insert,remove,clear)都是针对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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
mOriginalValues现在有一个原始值/项的副本,因此适配器可以完成其工作并通过mObjects显示已过滤的列表,而不会丢失预过滤的数据.
现在原谅我(并且请告诉和解释)如果我的想法不正确但我觉得这很奇怪,因为现在mOriginalValues不再为null,所有后续调用任何适配器操作都只会修改mOriginalValues.但是,由于适配器设置为将mObjects视为其主要数据集,因此屏幕上将显示没有任何事情发生.直到你执行另一轮过滤.删除过滤器会触发:
if (prefix == null || prefix.length() == 0) {
synchronized (mLock) {
ArrayList<T> list = new ArrayList<T>(mOriginalValues);
results.values = list;
results.count = list.size();
}
}
Run Code Online (Sandbox Code Playgroud)
mOriginalValues,我们自第一个过滤器以来一直在修改(虽然我们看不到它在屏幕上发生)存储在另一个列表中并复制到mObjects,最后显示所做的更改.不过从这一点开始它将是这样的:所有操作都将在mOriginalValues上完成,并且只有在过滤后才会出现更改.
至于解决方案,我现在想出的是(1)放置一个布尔标志,告诉适配器操作是否有正在进行的过滤 - 如果过滤完成,则复制内容of mOriginalValues to mObjects,或者(2)简单地调用适配器的Filter对象并传递一个空字符串*.getFilter().filter("")以在每次操作后强制过滤[也如BennySkogberg所建议的].
如果有人能够对这个问题有所了解或确认我刚刚做了什么,我们将不胜感激.谢谢!
归档时间: |
|
查看次数: |
9989 次 |
最近记录: |