Add delay after Platform.runLater runnable

2019-09-11 05:34发布

问题:

I'm really beginner with javaFX and probably I'm missing something, but here my issue: I should show some changes in my gui application sequentially.

My code looks like this (each method performs a change in the gui, but the final result is given by the last method of course):

public void updateGui()
{
    Platform.runLater(() -> {
        doFirstStuff();
        doSecondStuff();
        doThirdStuff();
    });
}

It would be nice if between the execution of each method there was a little delay (1,2 or maybe 3 seconds) for give time to the user to see what happened in the application.

My attempt was put:

Thread.sleep(1000);

after each method call, but since the thread is the JavaFX Application Thread, the result is awful.

Another solution that comes up right now in my mind is:

execute each method in another thread with a Runnable like this:

() -> {
    Platform.runLater(() -> {
        doFirstStuff();
    });
    Thread.sleep(1000);
});

and in updateGui() submit the task in a newSingleThreadExecutor() and wait for the termination of each task. But I don't know, it doesn't seem a good solution.

What is the best way to achieve my goal?

回答1:

The simplest way is just to use a Timeline:

public void updateGui() {
    final KeyFrame kf1 = new KeyFrame(Duration.seconds(0), e -> doFirstStuff());
    final KeyFrame kf2 = new KeyFrame(Duration.seconds(1), e -> doSecondStuff());
    final KeyFrame kf3 = new KeyFrame(Duration.seconds(2), e -> doThirdStuff());
    final Timeline timeline = new Timeline(kf1, kf2, kf3);
    Platform.runLater(timeline::play);
}

I am assuming here that updateGui() is being called on a background thread (otherwise just remove Platform.runLater(...) and call timeline.play() directly).

If you really want to get your hands dirty with threads, you could achieve the same (more or less) with

public void updateGui() {

    Thread thread = new Thread(() -> {
        try {
            Platform.runLater(() -> doFirstStuff());
            Thread.sleep(1000);
            Platform.runLater(() -> doSecondStuff());
            Thread.sleep(1000);
            Platform.runLater(() -> doThirdStuff());
        } catch (InterrupedException exc) {
            // should not be able to get here...
            throw new Error("Unexpected interruption");
        }
    };
    thread.start();
}

but I think for use cases like this, the Timeline (or other parts of the animation API) are much cleaner (and use fewer resources, since they don't create a new thread).