更新UI元素(如listview)必須從FX應用程序線程完成。 如果從後臺線程調用populateListView(),則在後臺更新observableList,導致listview嘗試從後臺更新。
使用Platform.runLater將observableList設置爲listview會發生在FX線程上,但在加載到listview後,observableList仍會在後臺更新。
new Thread(()->{
GluonObservableList<MyClass> items = DataProvider.retrieveList(restClient.createListDataReader(MyClass.class));
//Option 1
//listview.setItems(items);
//Option 2
//Platform.runLater(()->listview.setItems(items));
//Option 3
//items.initializedProperty().addListener((obv,ov,nv)->{
// listview.setItems(items);
//});
//Option 4
items.stateProperty().addListener((obvs,ovs,nvs)->{
if (nvs.equals(ConnectState.SUCCEEDED)) {
listview.setItems(items);
}else if(nvs.equals(ConnectState.FAILED)){
MobileApplication.getInstance().showMessage("Rest API request failed");
}
});
}).start();
選項1和選項2更新數據之前列表視圖被加載到observableList。選項1和2會拋出多個異常(而選項1只是醜陋的)。
在加載了observableList並在FX應用程序線程上處理後,選項3和選項4都會觸發listview更新。
或者,你可以包裝任何調用populateListView()在Platform.runLater
我想我的問題應該更精確...實際上我使用選項3,我認爲這是'GluonObservableList'應該被使用。我只是想知道爲什麼'DataProvider.retrieveList'中的'Iterator'沒有包含在'Platform.runLater()'中,這對我來說是完全有意義的。當你考慮一個你在不會更新UI的'Thread'中使用它的情況。 – jns
只需添加一個快速註釋到此,直接設置ListView上的項目是非常有意義的,如選項1中所示。因爲GluonObservableList是ObservableList,添加到它的任何項目將自動反映在ListView中控制,就像使用常規的ObservableList時一樣。對DataProvider.retrieveList的調用也必須在FX應用程序線程上執行。 Gluon Connect已經在它自己的後臺線程中實際檢索列表,所以開發人員沒有理由在FX應用程序線程之外調用它。 –
在這個例子中,我專門調用了DataProvider,並從後臺線程填充了選項1的列表視圖,這會產生一個錯誤。如果在FX線程上,這將起作用。選項2仍然產生錯誤,因爲DataProvider仍然從後臺調用。 DataProvider非常好用,因爲不需要去後臺線程來請求數據。 – AhaMoment