Aggiornamento dell’interfaccia utente da diversi thread in JavaFX

Sto sviluppando un’applicazione con diversi oggetti TextField che devono essere aggiornati per riflettere le modifiche nelle proprietà di back-end associate. I TextField non sono modificabili, solo il back-end può cambiare il loro contenuto.

Come ho capito, il modo corretto su questo è di eseguire il calcolo pesante su un thread separato in modo da non bloccare l’interfaccia utente. L’ho fatto usando javafx.concurrent.Task e comunicato un singolo valore al thread JavaFX usando updateMessage() , che funzionava bene. Tuttavia, ho bisogno di più di un valore per essere aggiornato mentre il back-end fa il suo crunch.

Poiché i valori back-end sono archiviati come proprietà JavaFX, ho provato semplicemente ad associarli a textProperty di ciascun elemento della GUI e lasciare che i binding facciano il lavoro. Questo non funziona, tuttavia; dopo aver eseguito per qualche istante, il campo di TextField interrompe l’aggiornamento anche se l’attività di back-end è ancora in esecuzione. Non vengono sollevate eccezioni.

Ho anche provato a utilizzare Platform.runLater() per aggiornare triggersmente i TextField anziché il bind. Il problema qui è che le attività runLater() sono programmate più velocemente di quanto la piattaforma possa eseguirle, e quindi la GUI diventa lenta e ha bisogno di tempo per “recuperare” anche dopo che l’attività di back-end è terminata.

Ho trovato alcune domande qui:

Le voci del logger tradotte nell’interfaccia utente smettono di essere aggiornate con il tempo

Il multithreading in JavaFX blocca l’interfaccia utente

ma il mio problema persiste.

In breve: ho un back-end che apporta modifiche alle proprietà e voglio che tali modifiche appaiano sulla GUI. Il back-end è un algoritmo genetico, quindi il suo funzionamento è suddiviso in generazioni discrete. Quello che vorrei è che i TextField aggiornino almeno una volta tra generazioni, anche se questo fa ritardare la generazione successiva. È più importante che la GUI risponda bene di quanto l’AG funzioni velocemente.

Posso pubblicare alcuni esempi di codice se non ho chiarito il problema.

AGGIORNARE

Sono riuscito a farlo seguendo il suggerimento di James_D. Per risolvere il problema del back-end che deve attendere la stampa della console, ho implementato una console bufferizzata di sorta. Memorizza le stringhe da stampare in un StringBuffer e le aggiunge automaticamente a TextArea quando viene chiamato un metodo flush() . Ho usato un AtomicBoolean per evitare che la prossima generazione si verifichi fino al completamento del flush, come avviene con un runnable Platform.runLater() . Si noti inoltre che questa soluzione è incredibilmente lenta.