Java8:可观察列表-在属性更改的情况下调用无效侦听器或更改侦听器

Java8:可观察列表-在属性更改的情况下调用无效侦听器或更改侦听器,java,properties,javafx,observable,changelistener,Java,Properties,Javafx,Observable,Changelistener,我构建了一个自定义属性并将其添加到可观察列表中。但如果属性内容发生更改,则不会调用侦听器。以下代码片段向您展示了“建筑”: public static final class TestObject { private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(); private final BooleanProperty selected = new SimpleBooleanProperty(f

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

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() +
                '}';
    }
}
这是我的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();
        });
    }
}
在这个测试中,您可以看到属性更改事件工作正常

@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());
}
@测试
公共void测试列表(){
最终AtomicInteger计数器=新的AtomicInteger(0);
最终ObservableList ObservableList=新ObservableList包装器(新ArrayList());
添加(新的TestProperty(“测试1”));
添加(新测试属性(“测试2”));
添加(新测试属性(“测试3”));
observableList.addListener(新的ListChangeListener(){
@凌驾

public void onChanged(Change每当修改列表中包含的属性时,ObservableList不会通知侦听器,而是在通知列表时通知侦听器

修改测试时可以看到这一点:

@Test
public void testList() {
    final AtomicInteger counter = new AtomicInteger(0);
    final ObservableList<TestProperty> observableList = new ObservableListWrapper<>(new ArrayList<>());

    observableList.addListener(new ListChangeListener<TestProperty>() {
        @Override
        public void onChanged(Change<? extends TestProperty> change) {
            System.out.println("**************");
            counter.incrementAndGet();
        }
    });

    observableList.add(new TestProperty("Test 1"));
    observableList.add(new TestProperty("Test 2"));
    observableList.add(new TestProperty("Test 3"));

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

    Assert.assertEquals(3, counter.intValue());
}
@测试
公共void测试列表(){
最终AtomicInteger计数器=新的AtomicInteger(0);
最终ObservableList ObservableList=新ObservableList包装器(新ArrayList());
observableList.addListener(新的ListChangeListener(){
@凌驾

public void onChanged(Change以下代码显示了可观察列表的一个简单实现,其中包含可观察值:

public class ObservableValueListWrapper<E extends ObservableValue<E>> extends ObservableListWrapper<E> {
 public ObservableValueListWrapper(List<E> list) {
  super(list, o -> new Observable[] {o});}}
public类observeValueListWrapper扩展了observeListWrapper{
公共ObservaleValueListWrapper(列表){
super(list,o->newobservable[]{o});}
或者,您必须使用POJO创建列表:

final ObservableList<MyPOJO> list = new ObservableListWrapper<>(new ArrayList(), o -> new Observable[] { new MyPOJOProperty(o) });
final observeList list=new observeListWrapper(new ArrayList(),o->new observeable[]{new MyPOJOProperty(o)});
或者你这样使用它:

final ObservableList<MyPOJO> list = new ObservableListWrapper<>(new ArrayList(), o -> { return new Observable[] {
o.value1Property(),
o.value2Property(),
...};});
final observeList list=new observeListWrapper(new ArrayList(),o->{return new observeable[]{
o、 value1Property(),
o、 value2Property(),
...};});

就是这样!谢谢。

创建一个可观察列表,该列表将发送“列表更新”通知如果列表元素的属性更改,则需要使用创建列表。
提取器
是一个
回调
,它将列表中的每个元素映射到一个
可观察
s数组。如果任何
可观察
s更改,
无效侦听器
s和
列表更改侦听器
s在名单上登记的人将收到通知

因此,在您的
testList()
方法中,您可以

final ObservableList<TestProperty> observableList = FXCollections.observableList(
    new ArrayList<>(),
    (TestProperty tp) -> new Observable[]{tp.selectedProperty()});
final ObservableList ObservableList=FXCollections.ObservableList(
新建ArrayList(),
(TestProperty tp)->新的可观察[]{tp.selectedProperty()});
如果标题可以更改,并且您还希望列表在更改时接收通知,您也可以这样做:

final ObservableList<TestProperty> observableList = FXCollections.observableList(
    new ArrayList<>(),
    (TestProperty tp) -> new Observable[]{tp.selectedProperty(), tp.titleProperty()});
final ObservableList ObservableList=FXCollections.ObservableList(
新建ArrayList(),
(TestProperty tp)->新的可观察[]{tp.selectedProperty(),tp.titleProperty()});

请注意,由于提取器是一个
回调函数(本质上是一个函数),因此实现可以任意复杂(根据另一个属性的值有条件地观察一个属性,等等).

但侦听器方法参数类中的“change.wasdupdated”是什么意思?是的,这里的javadoc有点混乱!这表示observablelist中链接到的项(即索引值为0、1、2等)是否已更新(即在该索引处放置了新对象),而不是对象本身已更改。这样做的目的是允许您在ListChangeListener中决定是否要在上注册ChangeListener(可能)列表中的ObservableProperty。应该注意的是,ObservableList不需要ObservableProperty作为成员,它可以保存对象类型。但有一些实现可以做到这一点,我想做的是:如果列表中的属性值发生了更改,则获取回调?嗯……我应该预料到questions=)我会说不。我没有遇到过它,我只是浏览了一下javadoc-那里没有什么值得注意的。但是,我认为装饰一个ObservableList来提供该功能是相当简单的。我将在上面添加一个快速示例。这太疯狂了:)列表有一个无效监听器,类似于可观察值的无效监听器。如果您有一个属性,则在该属性更改其值之一时调用无效监听器。我认为可观察列表必须具有与属性相同的行为:如果列表中的属性已更改,则必须调用无效监听器。Th我认为,必须检查添加的对象是否是一个可观察的值。不过,您正在复制API中的现有功能,还使用了不属于公共API的类。顺便说一句(尽管这与您的问题密切相关),
observeListWrapper
不是公共API的一部分,不应该真正使用。不保证它会出现在JavaFX的未来版本中。要创建
observeList
s(和其他可观察的集合),使用中的工厂方法。您可以举一个示例,其中您可以侦听类Person的ObservableList中的更改(侦听名称、姓氏等)。此示例没有为90%的情况提供简单示例:)看起来很有希望。如果可以的话,请提供一些澄清:有什么原因不能使用链表而不是数组列表吗?@Ruben9922使用链表进行了尝试,效果很好。@James_D实际上问题似乎出在我使用的
ChoiceBox
上,而不是
ObservableList
本身;列表本身可以很好地更新。
final ObservableList<TestProperty> observableList = FXCollections.observableList(
    new ArrayList<>(),
    (TestProperty tp) -> new Observable[]{tp.selectedProperty()});
final ObservableList<TestProperty> observableList = FXCollections.observableList(
    new ArrayList<>(),
    (TestProperty tp) -> new Observable[]{tp.selectedProperty(), tp.titleProperty()});