2015-06-16 14 views
6

Mam pytanie dotyczące wielowątkowości i powiązania StringProperty.Błąd wielowątkowości podczas wiązania StringProperty

Mam klasę CacheManager, która zawiera Thread, która aktualizuje moją pamięć podręczną ze zmianami na serwerze. Teraz chcę powiadomić użytkownika z tekstem i procentem postępu (które są Label i ProgressBar w JavaFX). Używam do tego celu publicznych statystyk: DoubleProperty i StringProperty, które są zdefiniowane w klasie CacheManager. Ja po prostu związać go tak:

progressBar.progressProperty().bind(CacheManager.progress); 
someLabel.textProperty().bind(CacheManager.status); 

Teraz w wątku Updater zaktualizować te Properties. Z DoubleProperty działa to dobrze, a ProgressBar doskonale pokazuje postęp. Jednak aktualizowanie Label ze statusem (który to tekst z StringProperty) wyrzuca błąd: java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-9

Teraz moje pytanie brzmi: Dlaczego praca DoubleProperty dobrze, natomiast StringProperty zgłasza błąd? Jaka jest różnica między nimi, biorąc pod uwagę wielowątkowość?

Wszelkie pomysły dotyczące przeprojektowania są również mile widziane i każda pomoc jest bardzo cenna!

+0

Szukałeś przyczyny "IllegalStateException: Nie w wątku aplikacji FX"? –

+0

Właśnie zgłasza błąd w aktualizacji 'Thread', kiedy próbuję zmienić tekst po raz drugi. A więc w tym wierszu: 'status.set (" Aktualizowanie ... ")' – bashoogzaad

+3

I * bet * jest tak, ponieważ skórka 'ProgressBar' ustawia' InvalidationListener' na 'progressProperty', podczas gdy skórka' Label' ustawia detektor zmian na 'textProperty'. Mimo, że zachowanie 'progressBar.progressProperty' jest wygodniejsze, myślę, że zachowanie' Label.textProperty' jest bardziej zwięzłe z tym, że wszystkie zmiany interfejsu muszą mieć miejsce w wątku UI. Użyj 'Platform.runLater()' lub weź pod uwagę klasę JavaFX 'javafx.concurrent.Service', która oferuje wymagane funkcje. –

Odpowiedz

10

Niewłaściwe jest wywoływanie kodu, który powoduje zmiany w interfejsie użytkownika z wątku innego niż wątek aplikacji FX, , niezależnie od tego, czy zgłasza wyjątek, czy nie, czy nie, zgłasza wyjątek. Zestaw narzędzi FX dokłada wszelkich starań, aby wyrzucić wyjątek, jeśli naruszysz tę regułę, ale w niektórych przypadkach wpływ na wydajność jest zbyt duży, aby wykonać test. Jeśli utworzysz te powiązania, wszelkie późniejsze zmiany właściwości, które zostały powiązane, muszą zostać wykonane w wątku aplikacji FX. To znaczy, jeśli są uruchomione w wątek tła, ty musi zmienić właściwości z kodem jak:

Platform.runLater(() -> CacheManager.progress.set(...)); 

i

Platform.runLater(() -> CacheManager.status.set(...)); 

Ponieważ prawdopodobnie nie chcesz, żeby Twój kod serwisowy być związany do JavaFX (za pośrednictwem klasy Platform), można rozważyć użycie słuchaczy zamiast wiązań i harmonogramu aktualizacji od słuchaczy:

CacheManager.progress.addListener((obs, oldValue, newValue) -> 
    Platform.runLater(() -> progressBar.setProgress(newValue.doubleValue()))); 
CacheManager.status.addListener((obs, oldStatus, newStatus) -> 
    Platform.runLater(() -> someLabel.setText(newStatus))); 

Jeśli zastąpisz wiązania tymi detektorami, możesz zaktualizować właściwości każdego wątku.

+0

Dziękuję za tę odpowiedź! Naprawdę wspaniale, że pokazujesz dwa sposoby na zrobienie tego! – bashoogzaad

+2

Ta odpowiedź w zasadzie sprowadza się do "nie wiążą właściwości w interfejsie"; to naprawdę jedyny sposób? Wygląda to na oczywistą wadę w projekcie JavaFX - jeśli zmiana właściwości musi nastąpić w wątku UI, powinien to być obowiązujący kod, aby to zrobić; nie powinieneś zmieniać modelu danych w wątku UI. –

+0

Często stosuję podejście polegające na dzieleniu modelu danych: dlatego często będę miał model interfejsu, który aktualizuje właściwości w wątku UI i odwołuje się do usługi lub podobnej. Model interfejsu użytkownika obserwuje zmiany w usłudze i propaguje te zmiany do zmian we własnych właściwościach, zarządzając wątkiem jako częścią tej propagacji. Następnie kontroler może powiązać widok z właściwościami modelu interfejsu użytkownika. Zobacz http://www.oracle.com/technetwork/articles/java/javafxinteg-2062777.html dla niektórych podobnych technik. –

Powiązane problemy