ListView控件不更新过滤后控件、ListView

2023-09-05 02:18:02 作者:我有故事没有酒

我有一个ListView(与setTextFilterEnabled(真))和一个自定义适配器(扩展ArrayAdapter),这是我从每当一个新的项目添加/插入主UI线程更新。一切工作正常在第一次 - 新项目立即显示在列表中。然而,这将停止的那一刻我试图筛选列表。

I have a ListView (with setTextFilterEnabled(true)) and a custom adapter (extends ArrayAdapter) which I update from the main UI thread whenever a new item is added/inserted. Everything works fine at first--new items show up in the list immediately. However this stops the moment I try to filter the list.

过滤工作,但我做了一次,我所有的成功尝试修改列表的内容(添加,删除),不显示了。我使用的日志,看看适配器的列表数据被正确地更新,而且它,但它不再是同步的显示ListView控件。

Filtering works, but I do it once and all of my succeeding attempts to modify the contents of the list (add, remove) don't display anymore. I used the Log to see if the adapter's list data gets updated properly, and it does, but it's no longer in sync with the ListView shown.

任何想法是什么造成这一点,如何更好地解决这个问题?

Any ideas what's causing this and how best to address the issue?

推荐答案

我经历了ArrayAdapter的实际来源$ C ​​$ C,它看起来就像是实际写入的行为是那样。

I went through ArrayAdapter's actual source code and it looks like it was actually written to behave that way.

ArrayAdapter有两个列表来开始:mObjects和mOriginalValues​​。 mObjects是主数据组,该适配器将与。服用add()函数,例如:

ArrayAdapter has two Lists to begin with: mObjects and mOriginalValues. mObjects is the primary data set that the adapter will work with. Taking the add() function, for example:

public void add(T object) {
    if (mOriginalValues != null) {
        synchronized (mLock) {
            mOriginalValues.add(object);
            if (mNotifyOnChange) notifyDataSetChanged();
        }
    } else {
        mObjects.add(object);
        if (mNotifyOnChange) notifyDataSetChanged();
    }
}

mOriginalValues​​最初为空,所以所有操作(添加,插入,删除,清除)默认情况下有针对性地mObjects。这是所有罚款,直到你决定的那一刻,让名单上的过滤和实际执行的。过滤首次初始化mOriginalValues​​与任何mObjects有:

mOriginalValues is initially null so all operations (add, insert, remove, clear) are by default targeted to mObjects. This is all fine until the moment you decide to enable filtering on the list and actually perform one. Filtering for the first time initializes mOriginalValues with whatever mObjects has:

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不失pre-过滤后的数据。

mOriginalValues now has a copy of, well, the original values/items, so the adapter could do its work and display a filtered list thru mObjects without losing the pre-filtered data.

现在原谅我(和请你告诉我们,解释),如果我的想法是不正确,但我觉得这真是奇怪,因为现在mOriginalValues​​不再为空,所有后续调用任何适配器操作只会更改mOriginalValues​​。然而,由于该适配器设置看mObjects作为主要的数据集,它会出现在屏幕上的什么也没有发生。也就是说,直到你完成了又一轮的筛选。拆卸过滤器触发这样的:

Now forgive me (and please do tell and explain) if my thinking is incorrect but I find this weird because now that mOriginalValues is no longer null, all subsequent calls to any of the adapter operations will only modify mOriginalValues. However since the adapter was set up to look at mObjects as its primary data set, it would appear on screen that nothing is happening. That is until you perform another round of filtering. Removing the filter triggers this:

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​​,并更改只会过滤后

mOriginalValues, which we've been modifying since our first filter (although we couldn't see it happening on screen) is stored in another list and copied over to mObjects, finally displaying the changes made. Nevertheless it will be like this from this point onwards: all operations will be done on mOriginalValues, and changes will only appear after filtering.

至于解决方案,就是我想出的时刻要么是(1)把一个布尔标志,它告诉适配器操作,如果有一个持续的过滤与否 - 如果筛选完成后,再复制在mOriginalValues​​对mObjects的内容,或(2)简单地调用适配器的筛选对象,并传递一个空字符串* .getFilter()。过滤器()每次操作后强制过滤器[如还BennySkogberg建议。

As for the solution, what I've come up with at the moment is either (1) to put a boolean flag which tells the adapter operations if there is an ongoing filtering or not--if filtering is complete, then copy over the contents of mOriginalValues to mObjects, or (2) to simply call the adapter's Filter object and pass an empty string *.getFilter().filter("") to force a filter after every operation [as also suggested by BennySkogberg].

这将是非常pciated,如果任何人都可以摆脱一些更多的光线在这个问题上或证实什么,我只是做AP $ P $。谢谢!

It would be highly appreciated if anybody can shed some more light on this issue or confirm what I just did. Thank you!

 
精彩推荐
图片推荐