Ответ 1
Я прошел через исходный код 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. Однако, поскольку адаптер был настроен для просмотра mObjects в качестве основного набора данных, на экране появлялось, что ничего не происходит. Это до тех пор, пока вы не выполните еще один раунд фильтрации. Удаление фильтра вызывает следующее:
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 Filter и передать пустую строку *.getFilter(). filter (""), чтобы заставить фильтр после каждой операции [также предложенный BennySkogberg].
Было бы весьма признательно, если кто-нибудь сможет пролить свет на эту проблему или подтвердить, что я только что сделал. Спасибо!