2017-06-03 205 views
1

爲了返回一個不可變觀察的名單我的API的客戶,我已經使用了FXCollections.unmodifiableObservableList(名單)包裝如下:FXCollections.unmodifiableObservableList的用途是什麼?

private final ObservableList<Person> persons = FXCollections.observableArrayList(); 

public ObservableList<Person> getPersons() { 
    return FXCollections.unmodifiableObservableList(persons); 
} 

然而,當客戶端增加了一個ListChangeListener到返回列表中,發生更改時不會收到通知。這顯然是因爲由FXCollections類創建的包裝器在包裝列表上設置了一個弱偵聽器,並且這個弱偵聽器被垃圾收集。

我錯過了這個包裝的東西嗎?

返回不可變的可觀察列表的正確方法是什麼?

回答

2

您現在處於正確的軌道上:包裝程序列表會將弱偵聽程序添加到包裝列表中,以避免內存泄漏,並且如果您不包含對包裝程序列表的引用,它將被垃圾收集。

看到這個測試(從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 } 
+0

所以基本上我需要的時候我回到有將堅持在除了原有的可觀察名單本身不可改變觀察到列表的引用附加字段屬性,並抑制警告不可變的領域。這不是開發者友好的。還有其他選擇嗎? –

+0

這是它被設計的方式。如果您查看了我發佈的鏈接(https://bugs.openjdk.java.net/browse/JDK-8088454),那麼這是推薦的解決方案。 –

+0

@StéphaneAppelcel:這個方法也與我的發現一致(在這裏)(https://stackoverflow.com/a/44343112/230513),儘管我歡迎任何額外的見解。 – trashgod

1

作爲參考,我profiled雖然幾個週期性和forced垃圾收集週期沒有seeng任何不幸 - 只有一個小的,世俗的,上升趨勢Integer實例積累的(有點人爲的)例子。添加到備份列表中的WeakListChangeListenerprivate implementation保存。當監聽程序變爲null並且不能再將更改轉發到不可修改列表的監聽程序時,弱監聽程序是removed。如果客戶的聽衆停止看到更改,則可能需要查看客戶如何管理由getPersons()返回的列表。

附錄:隨着音符WeakListChangeListener API中here通過@何佩雷達,「你必須保持到在,只要它是在使用中通過ListChangeListener的引用,否則會被垃圾收集太早。 「

changed { [0] added at 0 } 
… 
changed { [2162] added at 2162 } 

profile

import javafx.collections.FXCollections; 
import javafx.collections.ListChangeListener; 
import javafx.collections.ObservableList; 

/** 
* @see https://stackoverflow.com/a/44343112/230513 
*/ 
public class ObservableListTest { 

    public static void main(String[] args) throws Exception { 
     ObservableList<Integer> list1 = FXCollections.observableArrayList(); 
     ObservableList<Integer> list2 = FXCollections.unmodifiableObservableList(list1); 
     list2.addListener((ListChangeListener.Change<? extends Integer> c) -> { 
      System.out.println("changed " + c); 
     }); 
     int i = 0; 
     while (true) { 
      list1.add(Integer.valueOf(i++)); 
      Thread.sleep(1000); 
     } 
    } 
}