Android 筛选后ListView未更新
我有一个ListView(带有setTextFilterEnabled(true))和一个自定义适配器(extends ArrayAdapter),每当添加/插入新项时,我都会从主UI线程更新它。一开始一切正常——新项目立即出现在列表中。然而,当我尝试过滤列表时,这就停止了 过滤是有效的,但我只做了一次,以后所有修改列表内容的尝试(添加、删除)都不再显示。我使用日志查看适配器的列表数据是否得到了正确更新,确实得到了更新,但它不再与所示的ListView同步Android 筛选后ListView未更新,android,listview,filter,filtering,android-arrayadapter,Android,Listview,Filter,Filtering,Android Arrayadapter,我有一个ListView(带有setTextFilterEnabled(true))和一个自定义适配器(extends ArrayAdapter),每当添加/插入新项时,我都会从主UI线程更新它。一开始一切正常——新项目立即出现在列表中。然而,当我尝试过滤列表时,这就停止了 过滤是有效的,但我只做了一次,以后所有修改列表内容的尝试(添加、删除)都不再显示。我使用日志查看适配器的列表数据是否得到了正确更新,确实得到了更新,但它不再与所示的ListView同步 你知道是什么导致了这个问题,以及如何最
你知道是什么导致了这个问题,以及如何最好地解决这个问题吗?如果我很了解你的问题,你会调用notifyDataSetChanged()方法吗?它强制listview重新绘制自身
listAdapter.notifyDataSetChanged();
只要在执行某些操作(例如:延迟加载图像)以更新listview时使用此选项即可。我浏览了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,因此所有操作(添加、插入、删除、清除)默认都以mobject为目标。在您决定对列表启用筛选并实际执行筛选之前,这一切都是正常的。首次筛选将使用mObjects具有的任何对象初始化MoriginalValue:
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();
}
}
}
私有类ArrayFilter扩展了过滤器{
@凌驾
受保护的筛选器结果执行筛选(字符序列前缀){
FilterResults results=新的FilterResults();
if(mOriginalValues==null){
已同步(mLock){
mOriginalValues=新数组列表(mObjects);
//mOriginalValues不再为空
}
}
if(prefix==null | | prefix.length()==0){
已同步(mLock){
ArrayList=新的ArrayList(MoriginalValue);
结果.值=列表;
results.count=list.size();
}
}否则{
//过滤工作在这里进行,新的过滤集存储在newValues中
results.values=新值;
results.count=newValues.size();
}
返回结果;
}
@凌驾
受保护的void publishResults(CharSequence约束、FilterResults结果){
//未检查
mObjects=(列表)results.values;
如果(results.count>0){
notifyDataSetChanged();
}否则{
notifyDataSetionValidated();
}
}
}
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();
}
}
if(prefix==null | | prefix.length()==0){
已同步(mLock){
ArrayList=新的ArrayList(MoriginalValue);
结果.值=列表;
results.count=list.size();
}
}
mOriginalValues存储在另一个列表中,并复制到mObjects,最后显示所做的更改。我们从第一个过滤器开始就一直在修改mOriginalValues(尽管我们无法在屏幕上看到它发生)。然而,从这一点开始,情况将是这样的:所有操作都将在MoriginalValue上完成,并且只有在过滤之后才会出现更改
至于解决方案,我现在想到的是(1)放置一个布尔标志,告诉适配器操作是否有正在进行的过滤——如果过滤完成,然后将MoriginalValue的内容复制到mObjects,或者(2)简单地调用适配器的Filter对象并传递一个空字符串*.getFilter().filter(“”)在每次操作后强制执行过滤器[也由BennySkogberg建议]
如果有人能在这个问题上透露更多的信息或证实我刚才所做的事情,我将不胜感激。谢谢大家! 自2010年7月以来,该问题被报告为缺陷。看看我的首先我想说的是,@jhie的答案非常好。然而,这些事实并没有真正解决我的问题。但借助于对内部使用机制如何工作的了解,我可以编写自己的过滤函数:
public ArrayList<String> listArray = new ArrayList<>();
public ArrayList<String> tempListArray = new ArrayList<>();
public ArrayAdapter<String> tempAdapter;
public String currentFilter;
我用它在我的列表中实现了一个搜索功能
最大的优点是:您有更强大的过滤能力:在customFilterList()中,您可以轻松实现正则表达式的用法或将其作为一个案例使用
灵敏过滤器
而不是notifyDataSetChanged,您将调用updateList()
您将调用customFilterList('filter text'),而不是myListView.getFilter().filter('filter text')
目前,这只适用于一个ListView。也许,只要做一点工作,您就可以将其实现为一个自定义阵列适配器。我也遇到了同样的问题。然后我在StackOverflow上找到了一个帖子 在@MattDavis发布的答案中,传入的arraylist被分配给2个不同的arraylist
public PromotionListAdapter(Activity a, ArrayList<HashMap<String, String>> d)
{
activity = a;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new ImageLoader(activity.getApplicationContext());
//To start, set both data sources to the incoming data
originalData = d;
filteredData = d;
}
公共促销列表适配器(活动a,ArrayList d)
{
活动=a;
充气器=(LayoutInflater)activity.getSystemService(Context.LAYOUT\u充气器\u SERVICE);
imageLoader=新的imageLoader(activity.getApplicationContext());
//首先,将两者都设置为
// Defining filter functions
public void customFilterList(String filter){
tempListArray.clear();
for (String item : listArray){
if (item.toLowerCase().contains(filter.toLowerCase())){
tempListArray.add(item);
}
}
currentFilter = filter;
tempAdapter.notifyDataSetChanged();
}
public void updateList(){
customFilterList(currentFilter);
}
public PromotionListAdapter(Activity a, ArrayList<HashMap<String, String>> d)
{
activity = a;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new ImageLoader(activity.getApplicationContext());
//To start, set both data sources to the incoming data
originalData = d;
filteredData = d;
}