Я просмотрел фактический исходный код 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 изначально равен нулю, поэтому все операции (добавление, вставка, удаление, очистка) по умолчанию нацелены на объекты mObject. Это нормально, пока вы не решите включить фильтрацию в списке и фактически выполнить ее. Фильтрация впервые инициализирует 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 есть копия исходных значений / элементов, поэтому адаптер может выполнять свою работу и отображать отфильтрованный список через объекты mObject без потери предварительно отфильтрованных данных.
Теперь прости меня (и, пожалуйста, расскажи и объясни), что мое мышление неверно, но я нахожу это странным, потому что теперь, когда 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].
Буду очень признателен, если кто-нибудь сможет пролить немного света на этот вопрос или подтвердить то, что я только что сделал. Спасибо!