matte_colo
matte_colo

Reputation: 355

JavaFx and socket listener

we are developing a client-server application which has to work both with GUI and CLI. We have no problem with the CLI but we are struggling to implment it with JavaFX:

our server send some objects to the client (via socket) and these have to be processed.

This is our SocketServerListener (and writer):

public class SockeServerListener extends Thread implements ServerListener{
    private CliController controller;
    private ObjectInputStream in;
    private ObjectOutputStream out;

    public SocketServerListener(Socket server, CliController controller) throws UnknownHostException, IOException {
        this.controller = controller;
        this.out = new ObjectOutputStream(server.getOutputStream());
        this.in = new ObjectInputStream(server.getInputStream());
    }

    public void publishMessage(String message) throws IOException, RemoteException {
        out.writeObject(message);
        out.flush();
    }

    public void run() {
        try {
            while (true) {
                Dialogue dialogue = (Dialogue) in.readObject();
                controller.parseDialogue(dialogue);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


}

The SocketServerListener is instantiated by the controller which is the one who executes the who "executes" the received object, updating the interface (Cli/GUI)

public void parseDialogue(Dialogue dialog) {
        dialog.execute(view); //view is an interface extended by both the Cli and GUI
        this.canWrite = true;
    }

As I said, this works very well with the CLI, but it throws an exception with JavaFX

Exception in thread "Thread-7" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-7

We tried to use the Class used to generate all the GUI as controller, but without any (positive) result. How can we instantiate a thread so that it can work with JavaFX and call the methods that show the screens we need?

Thank you

Upvotes: 0

Views: 1415

Answers (2)

James_D
James_D

Reputation: 209653

Presumably the call to controller.parseDialogue(dialogue); is updating the UI. You can only do this on the FX Application Thread. You can schedule a runnable to execute on the FX Application Thread using Platform.runLater():

Platform.runLater( () ->  controller.parseDialogue(dialogue) );

Note that if you don't know you are executing this code in a context in which the FX toolkit has been started, the call to Platform.runLater(...) should be made in the controller instead, e.g.

public class NonGuiController implements CliController {

    @Override
    public void parseDialog(Dialogue dialogue) {
        // regular code here... 
    }
}

and

public class GuiController implements CliController {

    @Override
    public void parseDialogue(Dialogue dialogue) {
        // some preliminary work (still on background thread here) if necessary...
        Platform.runLater(() -> {
            // code that updates UI here...
        });
    }
}

and revert to the original code in your socket listener class.

Upvotes: 1

Puce
Puce

Reputation: 38142

Not on FX application thread

gives you the cause of the issue.

According to the Javadoc of the Node class:

Node objects may be constructed and modified on any thread as long they are not yet attached to a Scene in a Window that is showing. An application must attach nodes to such a Scene or modify them on the JavaFX Application Thread.

Use Platform.runLater to execute code on the FX application thread and also have a look at the javafx.concurrent package for further utility classes.

Upvotes: 2

Related Questions