Java 8:可观察列表 - 在属性更改时调用Invalidation Listener或Change Listener

use*_*962 5 java javafx properties observable changelistener

我构建一个自定义属性并将其添加到可观察列表中.但是如果属性内容发生更改,则不会调用侦听器.以下代码段显示了"构建":

public static final class TestObject {
    private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper();
    private final BooleanProperty selected = new SimpleBooleanProperty(false);

    public TestObject(String title) {
        this.title.set(title);
    }

    public String getTitle() {
        return title.get();
    }

    public ReadOnlyStringProperty titleProperty() {
        return title.getReadOnlyProperty();
    }

    public boolean getSelected() {
        return selected.get();
    }

    public BooleanProperty selectedProperty() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected.set(selected);
    }

    @Override
    public int hashCode() {
        return Objects.hash(title.get());
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        final TestObject other = (TestObject) obj;
        return Objects.equals(this.title.get(), other.title.get());
    }

    @Override
    public String toString() {
        return "TestObject{" +
                "title=" + title.get() +
                ", selected=" + selected.get() +
                '}';
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的POJO类,其内部属性值如name和selected.

public static final class TestProperty extends SimpleObjectProperty<TestObject> {
    public TestProperty(String name) {
        super(new TestObject(name));
        init();
    }

    public TestProperty(TestObject testObject) {
        super(testObject);
        init();
    }

    public String getTitle() {
        return getValue().getTitle();
    }

    public void setSelected(boolean selected) {
        getValue().setSelected(selected);
    }

    public boolean getSelected() {
        return getValue().getSelected();
    }

    public BooleanProperty selectedProperty() {
        return getValue().selectedProperty();
    }

    public ReadOnlyStringProperty titleProperty() {
        return getValue().titleProperty();
    }

    @Override
    public void set(TestObject testObject) {
        super.set(testObject);
        init();
    }

    @Override
    public void setValue(TestObject testObject) {
        super.setValue(testObject);
        init();
    }

    private void init() {
        if (get() == null)
            return;

        get().titleProperty().addListener((v, o, n) -> fireValueChangedEvent());
        get().selectedProperty().addListener((v, o, n) -> {
            fireValueChangedEvent();
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我基于POJO的自定义属性.所有属性更改都将为我的自定义属性触发更改事件.

@Test
public void testSimple() {
    final AtomicInteger counter = new AtomicInteger(0);
    final TestProperty testProperty = new TestProperty("Test");
    testProperty.addListener(observable -> {
        System.out.println("New state: " + testProperty.get().toString());
        counter.incrementAndGet();
    });

    testProperty.setSelected(true);
    testProperty.setSelected(false);

    Assert.assertEquals(2, counter.intValue());
}
Run Code Online (Sandbox Code Playgroud)

在此测试中,您可以看到属性更改事件正常工作.

@Test
public void testList() {
    final AtomicInteger counter = new AtomicInteger(0);
    final ObservableList<TestProperty> observableList = new ObservableListWrapper<>(new ArrayList<>());
    observableList.add(new TestProperty("Test 1"));
    observableList.add(new TestProperty("Test 2"));
    observableList.add(new TestProperty("Test 3"));

    observableList.addListener(new ListChangeListener<TestProperty>() {
        @Override
        public void onChanged(Change<? extends TestProperty> change) {
            System.out.println("**************");
        }
    });
    observableList.addListener((Observable observable) -> {
        System.out.println("New state: " + ((TestProperty) observable).get().toString());
        counter.incrementAndGet();
    });

    observableList.get(1).setSelected(true);
    observableList.get(2).setSelected(true);
    observableList.get(1).setSelected(false);
    observableList.get(2).setSelected(false);

    Assert.assertEquals(4, counter.intValue());
}
Run Code Online (Sandbox Code Playgroud)

但是在此代码中,您会看到,如果列表中的属性值已更改,则可观察列表不会调用失效侦听器,也不会调用更改侦听器.

怎么了?

谢谢.

Jam*_*s_D 20

要创建一个可观察列表,如果列表元素的属性发生更改,将发送"列表更新"通知,您需要使用提取器创建列表.的extractorCallback,该列表的每个元素映射到的阵列Observable秒.如果任何Observables更改,将通知在列表中注册的InvalidationListeners和ListChangeListeners.

所以在你的testList()方法中,你可以做到

final ObservableList<TestProperty> observableList = FXCollections.observableList(
    new ArrayList<>(),
    (TestProperty tp) -> new Observable[]{tp.selectedProperty()});
Run Code Online (Sandbox Code Playgroud)

如果标题能够更改,并且您还希望列表在发生时接收通知,那么您也可以这样做:

final ObservableList<TestProperty> observableList = FXCollections.observableList(
    new ArrayList<>(),
    (TestProperty tp) -> new Observable[]{tp.selectedProperty(), tp.titleProperty()});
Run Code Online (Sandbox Code Playgroud)

请注意,因为提取器是Callback(基本上是一个函数),所以实现可以是任意复杂的(根据另一个的值有条件地观察一个属性,等等).

  • 你能举一个例子来监听类 Person 的 ObservableList 的变化(监听名字、姓氏等?)这个例子没有为 90% 的情况提供一个简单的例子:) (3认同)