ObservableList: как надежно обнаружить setAll?

В некоторых контекстах необходимо обнаружить - в ListChangeListener, без контроля над самим списком - "все данные выгружены", т.е. когда нам нужно очистить какое-то состояние, например выборку — на совершенно новых данных старое состояние не имеет смысла.

Совершенно новые данные можно получить,

  • список.setAll(...)
  • list.set(otherObservableList), если список является ListProperty

Размышляя о том, какой тип изменений можно запустить в setAll (c — это изменение, items — наблюдаемый список, псевдокод «subChangeCount» для подсчета подизменений):

// initially empty
assertEquals(0, items.size());
items.setAll(1, 2, 4);
assertEquals(1, c.subChangeCount());
assertTrue(c.wasAdded() && !c.wasReplaced());
assertEquals(0, c.getFrom());
assertEquals(c.getList().size(), c.getAddedSize()); 

// initially not empty
assertTrue(items.size() > 0);
items.setAll(1, 2, 4);
assertEquals(1, c.subChangeCount());
assertTrue(c.wasReplaced());
assertEquals(0, c.getFrom());
assertEquals(c.getList().size(), c.getAddedSize()); 

Кажется, это позволяет проверить утилиту, например:

boolean wasSetOrClearedAll(Change c) {
   if (c.getList().isEmpty()) return true;
   c.next();
   if (c.getAddedSize() == c.getList().size()) return true; 
   return false; 
}  

Напротив, внутренний код fx, т.е. при прослушивании элементов ComboBox:

while (c.next()) {
   comboBox.wasSetAllCalled = comboBox.previousItemCount == c.getRemovedSize();
   ... 
}
comboBox.previousItemCount = getItemCount();

хранит старый itemCount и сравнивает его с текущим removeSize (что мне неудобно, старое состояние слишком часто устаревает, на мой вкус), тем не менее, есть большая вероятность, что я что-то упускаю с моим подходом.

Вопрос:

в каком контексте мой служебный метод потерпит неудачу (и основной подход правильно обнаружит setAll)?


person kleopatra    schedule 18.11.2014    source источник
comment
Какой конкретный тип ObservableList вы используете? Похоже, что ListProperty — это абстрактный класс, который не объявляет setAll(...)   -  person Zeki    schedule 02.12.2014
comment
@zeki хм .. все ObservableLists должны иметь элемент setAll(T...) - конечно, могут не поддерживаться, поэтому берите любой, в котором он реализован (ListProperty не представляет собой ничего особенного, он просто маршрутизирует setAll своего резервного списка)   -  person kleopatra    schedule 02.12.2014
comment
В таком случае, не могли бы вы расширить ListProperty и заставить setAll инициировать событие перед вызовом суперметода?   -  person Zeki    schedule 02.12.2014
comment
@Zeki хм .. похоже, мой вопрос не слишком ясен (постараюсь перефразировать его завтра :-) - моя точка зрения, если со стороны слушателя, просто видящего изменения без какого-либо контроля над отправителем.   -  person kleopatra    schedule 02.12.2014
comment
@downvoter - не хочешь объяснить?   -  person kleopatra    schedule 03.12.2014
comment
@kleopatra: я не понимаю твоего вопроса. Особенно assertEquals(0, c.getFrom());? Можете ли вы уточнить?   -  person Gigamegs    schedule 03.12.2014
comment
@kleopatra: Почему бы не очистить удаление/список?   -  person Gigamegs    schedule 03.12.2014
comment
@Phpdna Я слушатель - не хочу менять сам список, просто сделайте что-нибудь, если весь контент был заменен. Что касается c.getFrom(): setAll запускает замену, начиная с 0   -  person kleopatra    schedule 04.12.2014
comment
@kleopatra: IMO основной код безопаснее. Это гарантирует, что список тот же. Или вы можете использовать основной код и свое решение параллельно?   -  person Gigamegs    schedule 04.12.2014


Ответы (1)


К сожалению, нет надежного способа обнаружить это на стороне прослушивателя.

Борьба начинается с реализации по умолчанию, которая в основном выглядит так:

@Override
public boolean setAll(Collection<? extends E> col) {
    beginChange();
    try {
        clear();
        addAll(col);
    } finally {
        endChange();
    }
    return true;
}

Если вы передаете пустую коллекцию в setAll, результат и запускаемое событие точно такие же, как если бы вы вызвали clear.

Таким образом, ваш метод wasSetOrClearedAll возвращает true при вызове clear (как и базовая реализация).

Итак, в конце концов, нет общего обнаружения setAll, все зависит от вашего варианта использования. Если вы можете сузить то, что вы пытаетесь обнаружить, вы можете написать для этого фильтр.

person eckig    schedule 09.12.2014
comment
аааа ... даже не подумал посмотреть на реализацию ядра ;-) Хороший аргумент, спасибо! clear/setAll одинаково хорош - в основном мне нужны какие-то средства, чтобы надежно отбросить все состояния, связанные со старыми элементами (без ссылок на элементы, только на их прежние позиции). хм... снова к размышлениям - person kleopatra; 10.12.2014
comment
И ListChangeListener.Change.getRemoved() / getFrom() / getTo() недостаточно хорош для очистки? - person eckig; 10.12.2014
comment
хм... нет, если я следую основным реализациям selectionModels. Которые, однако, чертовски глючат. Наверное надо думать с нуля, может setAll не такой уж и частный случай, в конце концов :-) - person kleopatra; 10.12.2014