过滤后ListView不更新

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所建议的].

如果有人能够对这个问题有所了解或确认我刚刚做了什么,我们将不胜感激.谢谢!