Разбираю чужой код, и не могу понять, как он работает.
public class ChatClient implements Notifier {
private Set<MessageObserver> observers = new HashSet<>();
public void start(String name, String password) {
Receiver receiver = new Receiver();
receiver.start();
}
private class Receiver extends Thread {
@Override
public void run() {
try {
notifyObservers(new Message(-1000,"aa", "vv", "ss"));
} catch (IOException e) {
e.printStackTrace();
}
}
public interface MessageObserver {
void newPrivateMessageReceived(Message msg);
void newBroadCastMessageReceived(Message msg);
void sendMessageFailed(Message msg);
void newLoginAnnouncement(Message msg);
void newLogoutAnnouncement(Message msg);
void loginSuccessMessage(Message msg);
void loginFailedMessage(Message msg);
void registerSuccessMessage(Message msg);
void registerFailMessage(Message msg);
}
public interface Notifier {
void addMessageObserver(MessageObserver o);
void removeMessageObserver(MessageObserver o);
void notifyObservers(Message m);
}
@Override
public void notifyObservers(Message m) {
if (m == null) {
throw new NullPointerException("Message is null !");
}
for (MessageObserver observer : observers) {
observer.loginFailedMessage(m);
}}
public class LoginController implements MessageObserver {
private ChatClient model;
@FXML
private Stage stage;
@FXML
public Hyperlink registerHyperlink;
@FXML
TextField usernameField;
@FXML
PasswordField passwordField;
@FXML
Text resultMessage;
@FXML
BorderPane loginBorderPane;
public void initialise(ChatClient model) {
this.model = model;
}
@FXML
public void handleLoginAction(ActionEvent actionEvent) {
stage = (Stage) ((Node) actionEvent.getSource()).getScene().getWindow();
String username = usernameField.getText();
String password = passwordField.getText();
//TODO validate username and pass
model.start(username, password);
}
@Override
public void registerFailMessage(Message msg) {
resultMessage.setText(msg.getMessageBody());
}
}
public class ChatApp extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader loginLoader = new FXMLLoader(getClass().getResource("../resources/layouts/login_window.fxml"));
Parent root = loginLoader.load();
LoginController loginController = loginLoader.getController();
//setUserAgentStylesheet(STYLESHEET_MODENA);
ChatClient model = new ChatClient();
loginController.initialise(model);
model.addMessageObserver(loginController);
Scene scene = new Scene(root, 400, 400);
primaryStage.setTitle("Login");
primaryStage.setScene(scene);
primaryStage.show();
}
}
Суть в том, что из конроллера вызывается метод start, тот в свою очередь создает новый поток вызывая приватный класс Receiver, из нового потока вызывается метод notifyObservers, который меняет значение у текстового поля в контроллере. Но как такое возвожно, если это новый поток? Делаю точно так-же, мне выскакивает ошибка:
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
at com.coursework.controllers.LoginWindowController.loadMainWindows(LoginWindowController.java:40)
at com.coursework.logics.MainClient.d(MainClient.java:68)
at com.coursework.logics.MainClient$connectionToServer.run(MainClient.java:49)
А код, который выше - работает, может дело в интерфейсах?