InvalidationListener与ChangeListener

我有一个用例,我想将多个ObservableValue绑定到一个Observable ,因为我实际上并不感兴趣,值的变化是什么,我只需要一种方法在它发生变化时得到通知。

所以这是Observable绑定,我出现了:

 BooleanBinding() { { super.bind(proxy.activeShipProperty()); INavigableVessel activeShip = proxy.getActiveShip(); super.bind(activeShip.getLoadBinding()); if (activeShip instanceof IShip) { super.bind(((IShip) activeShip).travelState()); } else { super.bind(((IConvoy) activeShip).getOrlegShip().travelState()); } super.bind(date.dayDateBinding()); } private boolean value = true; @Override protected boolean computeValue() { value = !value; return value; } }; 

然后是这个测试代码,以validation它是否按预期工作:

 Observable observable = contentProvider.createObservable(ENoticeBoardType.SHIP_WARE_INFO, proxy); IntegerProperty invalidationCounter = new SimpleIntegerProperty(0); InvalidationListener listener = observable1 -> invalidationCounter.setValue(invalidationCounter.get() + 1); observable.addListener(listener); // When dayBinding.invalidate(); loadBinding.invalidate(); travelState.set(EShipTravelState.ANCHOR); activeVessel.set(mock(IShip.class)); // Then assertEquals(4, invalidationCounter.get()); 

事实certificate它没有。 invalidationCounter仅在第一次无效调用时增加一次。

但是当我从上面处理BooleanBinding作为ObservableValue ,我可以添加一个ChangeListener:

 ChangeListener listener = (obs, oldValue, newValue) -> invalidationCounter.setValue(invalidationCounter.get() + 1); observable.addListener(listener); // When dayBinding.invalidate(); loadBinding.invalidate(); travelState.set(EShipTravelState.ANCHOR); activeVessel.set(mock(IShip.class)); // Then assertEquals(4, invalidationCounter.get()); 

这按预期工作。

我想知道/已经确认:InvalidationListener只被调用一次,当Observable变为无效时,它不会变回有效,因此它可以再次变为有效。 但是,使用ChangeListener强制计算新值,因此ObservableValue再次变为有效。

基于这个观察,是否有任何用例我实际上可以使用Observable

Observable只是一个接口,实现确定,如果调用invalidate触发某个状态的监听器。 您在此处观察到的行为是BooleanBinding仅触发一次invalidation更新,直到使用get()方法检索该值。
一旦听众收到通知,观察者就会知道价值可能已经改变。

这是一种避免不必要计算的优化。 例如,考虑以下场景:有三个BooleanProperty s b1b2b3 ,你对b1 && (b2 || b3)感兴趣。 在这种情况下,如果b1false ,则可以应用短路评估,不需要您评估(b2 || b3) ,如果b2true ,则评估(b2 || b3)不要求您评估b3 。 如果b2和/或b3的计算成本很高,那么如果你可以避免它,那么它会使代码更难以评估它们,例如使用以下实现

 BooleanBinding binding = new BooleanBinding() { { bind(b1, b2, b3); } @Override protected boolean computeValue() { if (!b1.get()) { return false; } if (b2.get()) { return true; } else { return b3.get(); } // the above is basically a longer version of // return b1.get() && (b2.get() || b3.get()); // to highlight the short circuiting behaviour } }; 

InvalidationListener相比, ChangeListener需要将新值传递给它们,因此添加任何ChangeListenerinvalidation调用get() ,并且每个invalidation调用都会触发computeValue调用。