2

I am receiving strings from my server that I want to append into a Textarea on the client side (Think chat window). Problem is, when I receive the string, the client freezes.

insertUserNameButton.setOnAction((event) -> {
        userName=userNameField.getText();
        try {
            connect();
        } catch (IOException e) {
            e.printStackTrace();
        }
    });

public Client() {
    userInput.setOnAction((event) -> {

        out.println(userInput.getText());
        userInput.setText("");

    });
}

private void connect() throws IOException {

    String serverAddress = hostName;
    Socket socket = new Socket(serverAddress, portNumber);
    in = new BufferedReader(new InputStreamReader(
            socket.getInputStream()));
    out = new PrintWriter(socket.getOutputStream(), true);

    while (true) {
            String line = in.readLine();

        if (line.startsWith("SUBMITNAME")) {
            out.println(userName);

        } else if (line.startsWith("MESSAGE")) {
            Platform.runLater(()->serverOutput.appendText(line.substring(8) + "\n"));

        } else if (line.startsWith("QUESTION")) {
            Platform.runLater(()->serverOutput.appendText(line.substring(8) + "\n"));

        } else if (line.startsWith("CORRECTANSWER")) {
            Platform.runLater(()->serverOutput.appendText(line.substring(14) + "\n"));
        }
    }
}

public static void main(String[] args) {
    launch(args);
}

I have done some research and it seems that using Platform.runLater on each append should fix the problem. It doesn't for me.

Anyone has an idea of what it can be caused by? Thank you!

binerkin
  • 21
  • 3
  • Where are you calling `connect()`? On what thread? – James_D Apr 06 '17 at 15:28
  • I have edited the code. It's called from an action event. A connect button that initiates the connection. No thread. – binerkin Apr 06 '17 at 15:38
  • If you're calling it from an event handler, then it's running in the FX Application Thread. So your infinite `while (true) { ... }` loop is running on the FX Application thread, blocking it and preventing the UI from performing any updates. You need to run this on a background thread. – James_D Apr 06 '17 at 15:40
  • That makes sence! I'll try it out. Thank you very much! – binerkin Apr 06 '17 at 15:43

1 Answers1

2

You are calling connect() on the FX Application Thread. Since it blocks indefinitely via the

while(true) {
    String line = in.readLine();
    // ...
}

construct, you block the FX Application Thread and prevent it from doing any of its usual work (rendering the UI, responding to user events, etc).

You need to run this on a background thread. It's best to use a Executor to manage the threads:

private final Executor exec = Executors.newCachedThreadPool(runnable -> {
    Thread t = new Thread(runnable);
    t.setDaemon(true);
    return t ;
});

and then do

insertUserNameButton.setOnAction((event) -> {
    userName=userNameField.getText();
    exec.execute(() -> {
        try {
            connect();
        } catch (IOException e) {
            e.printStackTrace();
        }
    });
});
James_D
  • 201,275
  • 16
  • 291
  • 322