Issues appending text to a TextArea (JavaFX 8)

2019-02-26 22:20发布

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!

1条回答
成全新的幸福
2楼-- · 2019-02-26 23:19

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();
        }
    });
});
查看更多
登录 后发表回答