Water
Water

Reputation: 3665

Requesting the JavaFX thread to call some code without using Platform.runLater

In an application I'm making, I'd like to have everything done on one thread. I'd like to introduce some network IO that is asynchronous. I figure I'd keep it on one thread to reduce complications and just use a Channel/Selector.

Is there a way for the main JavaFX thread to periodically (or at the end of its logic) call a block of code. I'd prefer it to do it frequently in this case to always keep the application up to date.

I've tried searching around for how to do this and I've had no luck.

If I am to make some ASCII art out of this:

|                    Is there a gap here I can run the code in?
|                                V
|[JavaFX thread]--------------o     --------------o       --------------o
|                             ^
|                     Here all the UI work is done and it pauses before starting again

I have no idea if this is actually how the JavaFX thread works. I figure somewhere along the way after doing all the graphic updating and logic, it takes a break and calls any Runnable's to be executed by Platform.runLater. The problem here is I don't want to spam it with new Runnables all the time, I'm guessing this is bad practice?

Ideally I'd like to have it so the main JavaFX thread does all its logic, and then it polls for any input from the network connection. This should run even when the user is doing nothing (which therefore means I cannot rely on user input events to trigger socket reading).

Is there a way to do this?

Note: The data received from the socket will interact with stuff in the JavaFX modules, so there's even more reason to keep it on the main JavaFX thread.

Upvotes: 0

Views: 272

Answers (2)

mipa
mipa

Reputation: 10650

Look at the AnimationTimer class. It does exactly what you are looking for.

Upvotes: 1

Tomas Mikula
Tomas Mikula

Reputation: 6537

You can do that, but be advised that it may block your UI when the processing takes too long. You can abuse Timeline or PauseTransition for that, or you can use a convenient wrapper from ReactFX.

PauseTransition

PauseTransition pt = new PauseTransition(Duration.millis(500));
pt.setOnFinished(ae -> {
    // do your work here, it runs on the JavaFX application thread
});
SequentialTransition seq = new SequentialTransition(pt);
seq.setCycleCount(Animation.INDEFINITE);
seq.play();

Timeline

Timeline timeline = new Timeline(new KeyFrame(
        Duration.millis(500),
        ae -> {
            // do your work here, it runs on the JavaFX application thread
        }));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();

ReactFX

FxTimer.runPeriodically(
        Duration.ofMillis(500),
        () -> {
            // do your work here, it runs on the JavaFX application thread
        });

Upvotes: 2

Related Questions