InvalidationListener与ChangeListener

时间:2018-07-21 05:21:22

标签: java javafx listener

我有一个用例,我想将多个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;
    }
};

然后是此测试代码,以验证其是否按预期工作:

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());

事实并非如此。在第一个无效调用中,invalidationCounter仅增加一次。

不过,当我从上方以ObservableValue处理BooleanBinding时,可以添加一个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的任何用例吗?

1 个答案:

答案 0 :(得分:4)

std::less只是一个接口,由实现确定是否调用Observable会以某种状态触发侦听器。您在此处观察到的行为是invalidate仅触发一次BooleanBinding更新,直到使用invalidation方法检索到值为止。
希望观察者知道一旦通知了听者,该值可能会发生变化。

这是为了避免不必要的计算而进行的优化。例如。请考虑以下情形:有三个get()BooleanPropertyb1b2,而您对b3感兴趣。在这种情况下,如果b1 && (b2 || b3)(b2 || b3),则可以应用不需要评估b1的短路评估,而评估false不需要评估{{1 }},如果(b2 || b3)b3。如果b2和/或true的计算成本很高,则可以避免不评估它们,从而使代码的性能更高,例如可以避免。使用以下实现

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 } }; 要求将新值传递给他们,因此添加任何ChangeListener会导致调用InvalidationListener并导致每个{{1} }通话会触发ChangeListener的通话。