Dylan Russell
Dylan Russell

Reputation: 1098

Clarify when and where new threads are started and stopped

I followed an online tutorial for building a splash screen for my JavaFX application. Here is the SplashController file:

package splash;

import java.io.IOException;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * SplashController controls the Splash.FXML file. This is the initial software display. After a 
 * designated amount of time, the MainMenu.FXML is run.  
 *
 */
public class SplashController {

@FXML 
private StackPane splashRoot;
@FXML
private ImageView splashImage;

/**
 * Called after all @FXML annotated members have been injected. Starts a new thread "SplashScreen()".
 */
@FXML void initialize() {

    new SplashScreen().start(); //Start SplashScreen thread.

}

/**
 * Inner class that extends thread. Displays the splash screen for a designated amount of time then loads
 * MainMenu.FXML, sets a new stage, and displays the main menu. Hides the splash screen.
 *
 */
class SplashScreen extends Thread {

    @Override
    public void run() {

        try {

            splashImage.fitWidthProperty().bind( splashRoot.widthProperty() );  // binds the image to the rootPane width.
            Thread.sleep( 3000 ); // puts the thread (SplashScreen) to sleep in order to allow the splash to display long enough.

            Platform.runLater( new Runnable() { // Forces the main menu scene to load onto the SplashScreen thread when it is available.

                @Override
                public void run() {

                    FXMLLoader loader = new FXMLLoader( getClass().getResource( "../mainMenu/MainMenu.FXML" ) ); // Places MainMenu.FXML into the loader.
                    Stage stage = new Stage(); // Creates a new stage.

                    try {

                        stage.setScene( new Scene( loader.load() )  ); // Sets the scene using the root node of the loaded FXML document.

                    } catch ( IOException e ) {

                        e.printStackTrace();

                    }

                    stage.setResizable(false); // Prevents user from resizing the window.
                    stage.setTitle( "Test" ); // Sets the stage title.
                    stage.show(); // Displays the stage.
                    splashRoot.getScene().getWindow().hide(); // Hides the splash screen and presumably ends the SplashScreen thread.

                }

            });

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

} 
}

I have tried to annotate my understanding of how the threads are working here and was hoping you could either clarify for me if the following are correct or answer the question:

1) If I was to never create any new classes that extend thread or create any new Runnable() objects, I could assume that everything in my JavaFX project is running on a single JavaFX application thread;

2) When I create the inner class SplashScreen extends Thread and call start() on it, am I creating a second thread? So I therefore have two threads - the regular JavaFX application thread and the SplashScreen thread;

3) When I then call Platform.runLater( new Runnable() { .... } ) does it set that new stage, FXML, and controller in the JavaFX application thread, the SplashScreen thread, or yet a new third thread?

4) When I call splashRoot.getScene().getWindow().hide(), does that end the SplashScreen thread? Or is that thread continuing with the new Runnable() that was called by Platform.runLater()?

Upvotes: 0

Views: 177

Answers (1)

Jai
Jai

Reputation: 8363

1) If I was to never create any new classes that extend thread or create any new Runnable() objects, I could assume that everything in my JavaFX project is running on a single JavaFX application thread;

That is true as long you don't call anything (e.g. from other API) that does that.

2) When I create the inner class SplashScreen extends Thread and call start() on it, am I creating a second thread? So I therefore have two threads - the regular JavaFX application thread and the SplashScreen thread;

Yes. Do note that SplashScreen uses Platform.runLater() when it needs to handle UI stuff.

3) When I then call Platform.runLater( new Runnable() { .... } ) does it set that new stage, FXML, and controller in the JavaFX application thread, the SplashScreen thread, or yet a new third thread?

The code calling Platform.runLater() is on the second thread. The Runnable object inside Platform.runLater() is an object that is put inside JavaFX Application Thread's "queue," which the thread will run after it has completed whatever it is doing or needs to do (i.e. render UI etc).

4) When I call splashRoot.getScene().getWindow().hide(), does that end the SplashScreen thread? Or is that thread continuing with the new Runnable() that was called by Platform.runLater()?

It simply closes the window that is hosting your splash screen. The thread ends because it is the last line of code in the Runnable that the thread has to do . The thread ends because there is nothing else to do after placing the Runnable onto the JavaFX Application Thread queue.

Summary

  1. You created a window that shows the splash screen.
  2. In the controller's constructor, you created another thread.
  3. In that thread, you let it (that new thread) sleep for 3000ms.
  4. After it wakes up, you move back to JavaFX Application Thread, and in there you load new content and open new window, and closes the splash screen.

Upvotes: 2

Related Questions