当前位置: 首页 > 面试题库 >

Java 8:可观察列表-在属性更改的情况下,将调用Invalidation Listener或Change Listener

茅星雨
2023-03-14
问题内容

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

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

这是我基于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());
}

在此测试中,您可以看到属性更改事件正常运行。

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

但是在此代码中,您可以看到,如果列表中的属性值已更改,则可观察列表既不称为无效侦听器,也不称为更改侦听器。

怎么了?

谢谢。


问题答案:

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

所以用你的testList()方法,你可以做

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

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



 类似资料:
  • 我最近才知道,我们必须在Angular破坏组件之前取消订阅,否则会造成内存泄漏。 我还知道,我们可以获得对订阅的引用,通过对该订阅调用unsubscribe方法,我们可以进行订阅。例如: 下面的方法会起作用吗?在HTTP调用的情况下,退订是最好的方法吗?

  • 问题内容: 我只是阅读了watch()方法的Mozilla文档。它看起来非常有用。 但是,我找不到与Safari类似的东西。既不是Internet Explorer。 您如何管理跨浏览器的可移植性? 问题答案: 我不久前为此创建了一个小object.watch垫片。它适用于IE8,Safari,Chrome,Firefox,Opera等。

  • 问题内容: 我正在尝试将项目设置为表视图,但是setitems方法需要一个可观察的列表,而我的模型中却有一个可观察的集合.FXCollections实用程序类没有给定可观察的集合来创建可观察的列表的方法。类强制转换异常(按预期)。 目前,我正在使用这种代码 而且我有一些问题: 在表中进行编辑是否会按预期更新基础集? 这是这样做的“正确”方法吗 简而言之,我需要样式指南或最佳做法,以便在可观察集和可

  • 我有多个热观测器,它们可能发射也可能不发射项目。因此,我想把可观察项组合起来,然后如果其中任何一个发出结果,就处理结果,但如果其他可观察项在item发出,就应该一起处理。 还有可能在之前发出 最接近我所需要的,但只有当所有可观察到的对象发出至少一个项时才会发出结果。这个有无反应操作符吗?

  • 我有一个字段,上面有一个客户文本观察者。在一段代码中,我需要更改EditText中的值,我使用<code>.setText(“whather”)来执行此操作。 问题是,只要我做了更改,就会调用<code>afterextchanged 我需要 afterTextChanged 方法中的文本,因此不建议删除 。