为了将不可变的可观察列表返回给我的API的客户端,我使用了FXCollections.unmodifiableObservableList(list)包装器,如下所示:
private final ObservableList<Person> persons = FXCollections.observableArrayList();
public ObservableList<Person> getPersons() {
return FXCollections.unmodifiableObservableList(persons);
}
但是,当客户端将ListChangeListener添加到返回的列表时,在发生更改时不会收到通知。这显然是因为FXCollections类创建的包装器在包装列表上设置了一个弱侦听器,并且这个弱侦听器被垃圾收集。
我是否想念这个包装器?
返回不可变的可观察列表的正确方法是什么?
答案 0 :(得分:4)
你走在正确的轨道上:包装器列表为包装列表添加了一个弱侦听器,以避免内存泄漏,如果你没有保存对包装器列表的引用,它将被垃圾收集。
参见此测试(取自here):
private ObservableList<String> s = FXCollections.observableArrayList();
@Override
public void init() throws Exception {
FXCollections.unmodifiableObservableList(s).addListener((ListChangeListener.Change<? extends String> c) ->
System.out.println(c));
s.setAll("A1");
s.setAll("A2");
System.gc();
s.setAll("A3"); // <- Doesn't trigger the listener
}
打印:
{ [A1] added at 0 }
{ [A1] replaced by [A2] at 0 }
但是如果您添加对列表的引用:
private ObservableList<String> s = FXCollections.observableArrayList();
@Override
public void init() throws Exception {
// create a reference
final ObservableList<String> wrapperList = FXCollections.unmodifiableObservableList(s);
wrapperList.addListener((ListChangeListener.Change<? extends String> c) ->
System.out.println(c));
s.setAll("A1");
s.setAll("A2");
System.gc();
s.setAll("A3"); // <- Triggers the listener
}
现在打印:
{ [A1] added at 0 }
{ [A1] replaced by [A2] at 0 }
{ [A2] replaced by [A3] at 0 }
答案 1 :(得分:1)
作为参考,我profiled下面的(有点人为的)例子虽然有几个周期性的和forced垃圾收集周期没有任何不合适的东西 - 只有一个小的,世俗的,向上的趋势作为{{1的实例累积。添加到支持列表中的WeakListChangeListener
由private implementation保留。当侦听器变为Integer
并且无法再将更改转发到不可修改列表的侦听器时,弱侦听器将从备份列表中removed。如果客户端的侦听器停止看到更改,您可能需要查看客户端如何管理null
返回的列表。
附录:正如WeakListChangeListener
API中的注释和{JoséPereda的here所述,“您必须保留对传入的getPersons()
的引用,只要它在使用,否则将很快收集垃圾。“
ListChangeListener
changed { [0] added at 0 }
…
changed { [2162] added at 2162 }