Das Aktualisieren eines UI-Elements (z. B. Listview) muss über den FX-Anwendungs-Thread erfolgen. Wenn populateListView() von einem Hintergrundthread aufgerufen wird, wird die ObservableList im Hintergrund aktualisiert, was dazu führt, dass Listview versucht, vom Hintergrund aus zu aktualisieren.
Das Setzen der ObservableList auf die Listview mit Platform.runLater erfolgt auf dem FX-Thread, aber die ObservableList wird weiterhin im Hintergrund aktualisiert, nachdem sie in die Listview geladen wurde.
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();
Option 1 und Option 2 Aktualisierung der Listenansicht, bevor die Daten an die observableList geladen. Option 1 und 2 werfen mehrere Ausnahmen (und Option 1 ist nur hässlich).
Sowohl Option 3 als auch Option 4 lösen das Listview-Update aus, nachdem die ObservableList geladen wurde und im FX-Anwendungs-Thread behandelt wird.
Alternativ können Sie jeden Aufruf an populateListView() in Platform.runLater
Wrap Ich denke, meine Frage hätte präzisieren sollen ... Eigentlich verwende ich Option 3, die ich denke, ist die Art und Weise 'GluonObservableList' ist soll benutzt werden. Ich habe mich nur gefragt, warum der 'Iterator' in' DataProvider.retrieveList' nicht in ein 'Platform.runLater()' eingeschlossen ist, was für mich nun vollkommen Sinn macht, z.B. wenn Sie eine Situation betrachten, in der Sie sie in einem 'Thread' verwenden, der die Benutzeroberfläche nicht aktualisiert. – jns
Fügen Sie dazu einfach einen kurzen Kommentar hinzu, es macht jedoch durchaus Sinn, die Elemente in einer ListView direkt zu setzen, wie in Option 1. Da die GluonObservableList eine ObservableList ist, werden alle Elemente, die hinzugefügt werden, automatisch in der ListView angezeigt Kontrolle, genau wie wenn Sie eine reguläre ObservableList verwenden. Der Aufruf von DataProvider.retrieveList muss auch im FX-App-Thread ausgeführt werden. Gluon Connect führt den eigentlichen Abruf der Liste bereits in seinem eigenen Hintergrundthread durch, sodass es keinen Grund gibt, dass ein Entwickler dies von außerhalb des FX-Appthreads aufrufen würde. –
In dem Beispiel habe ich speziell DataProvider aufgerufen und die Listenansicht von einem Hintergrundthread für die Option 1. gefüllt, die einen Fehler erzeugte. Dies würde funktionieren, wenn auf dem FX-Thread. Option 2 erzeugt immer noch Fehler, da DataProvider noch aus dem Hintergrund aufgerufen wird. DataProvider funktioniert gut, da es nicht notwendig ist, zu einem Hintergrundthread zu gehen, um Daten anzufordern. – AhaMoment