ListView, не обновляющий после фильтрации

У меня есть ListView (с (верным) setTextFilterEnabled), и пользовательский адаптер (расширяет ArrayAdapter), который я обновляю от основного потока UI каждый раз, когда новый объект добавляется/вставляется. Все хорошо работает сначала - новые объекты сразу обнаруживаются в списке. Однако это останавливает момент, я пытаюсь отфильтровать список.

При фильтрации работ, но я делаю это однажды, и все мои последующие попытки изменить содержание списка (добавьте, удалите), больше не отображаются. Я использовал Журнал, чтобы видеть, обновляются ли данные списка адаптера правильно, и это делает, но это больше не находится в синхронизации с показанным ListView.

Какие-либо идеи, что вызывает это и как лучше всего решить проблему?

14
задан jhie 5 August 2010 в 12:07
поделиться

2 ответа

Я просмотрел фактический исходный код 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. Это нормально до тех пор, пока вы не решите включить фильтрацию в списке и не выполните ее. Фильтрация в первый раз инициализирует mOriginalValues ​​с тем, что есть у mObjects:

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.Однако, поскольку адаптер был настроен на просмотр объектов mObject в качестве основного набора данных, на экране могло показаться, что ничего не происходит. Это до тех пор, пока вы не выполните еще один раунд фильтрации. Удаление фильтра вызывает следующее:

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].

Был бы очень признателен, если бы кто-нибудь мог пролить больше света на этот вопрос или подтвердить то, что я только что сделал. Спасибо!

16
ответ дан 1 December 2019 в 13:58
поделиться

Если я хорошо понимаю вашу проблему - вы вызываете метод notifyDataSetChanged ()? Это заставляет список перерисовываться.

listAdapter.notifyDataSetChanged();

просто используйте это всякий раз, когда вы что-то делаете (например, ленивая загрузка изображений) для обновления списка.

0
ответ дан 1 December 2019 в 13:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: