【问题标题】:InvalidationListener vs. ChangeListenerInvalidationListener 与 ChangeListener
【发布时间】:2018-12-29 09:17:14
【问题描述】:

我有一个用例,我想将多个ObservableValues 绑定到一个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 仅在第一次 invalidate 调用时增加一次。

但是,当我将上面的 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

【问题讨论】:

    标签: java javafx listener


    【解决方案1】:

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

    这是避免不必要计算的优化。例如。考虑以下场景:有三个BooleanPropertys b1b2b3,您对b1 && (b2 || b3) 感兴趣。在这种情况下,您可以应用不需要您评估(b2 || b3) 的短路评估,如果b1false 并且评估(b2 || b3) 不需要您评估b3,如果b2 是@987654337 @。如果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
        }
    };
    

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

    【讨论】:

      猜你喜欢
      • 2020-10-18
      • 1970-01-01
      • 2014-01-01
      • 2011-10-11
      • 2017-05-10
      • 1970-01-01
      • 2017-12-24
      • 1970-01-01
      相关资源
      最近更新 更多