Exploring JavaFX's Application class

Tour JavaFX's Application class and learn about its capabilities

JavaFX applications are based on JavaFX's Application class. Perhaps you are unfamiliar with this class and have questions about using Application and on what this class offers your application code. This post attempts to answer these questions while exploring Application.

Introducing Application

The javafx.application.Application class provides a framework for managing a JavaFX application. This application must include a class that extends Application, overriding various methods that the JavaFX runtime calls to execute application-specific code.

An application can call Application methods to obtain startup parameters, access host services, arrange to launch itself as a standalone application, interact with the preloader (a small application that's started before the main application to customize the startup experience), and access the user agent (Web browser) style sheet.

Application life cycle

One of Application's tasks is to manage the application's life cycle. The following overridable Application methods play a role in this life cycle:

  • void init(): Initialize an application. An application may override this method to perform initialization before the application is started. Application's init() method does nothing.
  • void start(Stage primaryStage): Start an application. An application must override this abstract method to provide the application's entry point. The primaryStage argument specifies a container for the user interface.
  • void stop(): Stop an application. An application may override this method to prepare for application exit and to destroy resources. Application's stop() method does nothing.

The JavaFX runtime interacts with an application and invokes these methods in the following order:

  1. Create an instance of the class that extends Application.
  2. Invoke init() on the JavaFX Launcher Thread. Because init() isn't invoked on the JavaFX Application Thread, it must not create javafx.scene.Scene or javafx.stage.Stage objects, but may create other JavaFX objects.
  3. Invoke start() on the JavaFX Application Thread after init() returns and the JavaFX runtime is ready for the JavaFX application to begin running.
  4. Wait for the application to finish. The application ends when it invokes javafx.application.Platform.exit() or when the last window has been closed and Platform's implicitExit attribute is set to true.
  5. Invoke stop() on the JavaFX Application Thread. After this method returns, the application exits.

JavaFX creates an application thread, which is known as the JavaFX Application Thread, for running the application's start() and stop() methods, for processing input events, and for running animation timelines. Creating JavaFX Scene and Stage objects as well as applying scene graph modification operations to live objects (those objects already attached to a scene) must be done on the JavaFX Application Thread.

The java launcher tool loads and initializes the specified Application subclass on the JavaFX Application Thread. If there is no main() method in the Application class, or if the main() method calls Application.launch(), an instance of the Application subclass is constructed on the JavaFX Application Thread.

The init() method is called on the JavaFX Launcher Thread, which is the thread that launches the application; it's not called on the JavaFX Application Thread. As a result, an application must not construct a Scene or Stage object in init(). However, an application may construct other JavaFX objects in the init() method.

Listing 1 presents a simple JavaFX application that demonstrates this life cycle.

Listing 1. LifeCycle.java

import javafx.application.Application;
import javafx.application.Platform;

import javafx.stage.Stage;

public class LifeCycle extends Application
{
   @Override
   public void init()
   {
      System.out.printf("init() called on thread %s%n", 
                        Thread.currentThread());
   }

   @Override
   public void start(Stage primaryStage)
   {
      System.out.printf("start() called on thread %s%n", 
                        Thread.currentThread());
      Platform.exit();
   }

   @Override
   public void stop()
   {
      System.out.printf("stop() called on thread %s%n", 
                        Thread.currentThread());
   }
}

Compile Listing 1 as follows:

javac LifeCycle.java

Run the resulting LifeCycle.class as follows:

java LifeCycle

You should observe the following output:

init() called on thread Thread[JavaFX-Launcher,5,main]
start() called on thread Thread[JavaFX Application Thread,5,main]
stop() called on thread Thread[JavaFX Application Thread,5,main]

The output reveals that init() is called on a different thread than start() and stop, which are called on the same thread. Because different threads are involved, you may need to use synchronization.

If you comment out Platform.exit(), you won't observe the stop() called on thread Thread[JavaFX Application Thread,5,main] message because the JavaFX runtime won't invoke stop() -- the application won't end.

Application parameters

Application provides the Application.Parameters getParameters() method for returning the application's parameters, which include arguments passed on the command line, unnamed parameters specified in a JNLP (Java Network Launch Protocol) file, and <name,value> pairs specified in a JNLP file.

Application.Parameters encapsulates the parameters and provides the following methods for accessing them:

  • Map<String,String> getNamed(): Return a read-only map of the named parameters. The map may be empty but is never null. Named parameters include <name,value> pairs explicitly specified in a JNLP file, and any command-line arguments of the form: --name=value.
  • List<java.lang.String> getRaw(): Return a read-only list of the raw arguments. This list may be empty but is never null. For a standalone application, it's the ordered list of arguments specified on the command line. For an applet or WebStart application, it includes unnamed parameters as well as named parameters. For named parameters, each <name,value> pair is represented as a single argument of the form --name=value.
  • List<String> getUnnamed(): Return a read-only list of the unnamed parameters. This list may be empty but is never null. Named parameters (which are represented as <name,value> pairs) are filtered out.

Listing 2 presents a simple JavaFX application that demonstrates these methods.

Listing 2. Parameters.java

import java.util.List;
import java.util.Map;

import javafx.application.Application;
import javafx.application.Platform;

import javafx.stage.Stage;

public class Parameters extends Application
{
   @Override
   public void start(Stage primaryStage)
   {
      Application.Parameters parm = getParameters();
      System.out.printf("Named parameters: %s%n", parm.getNamed());
      System.out.printf("Raw parameters: %s%n", parm.getRaw());
      System.out.printf("Unnamed parameters: %s%n", parm.getUnnamed());
      Platform.exit();
   }
}

Compile Listing 2 as follows:

javac Parameters.java

Run the resulting Parameters.class as follows:

java Parameters a b c --name=w -name2=x --foo=y -foo=z bar=q

You should observe the following output:

Named parameters: {foo=y, name=w}
Raw parameters: [a, b, c, --name=w, -name2=x, --foo=y, -foo=z, -bar=q]
Unnamed parameters: [a, b, c, -name2=x, -foo=z, -bar=q]

Host services

Application provides the HostServices getHostServices() method for accessing the host services provider, which lets the application obtain its code and document bases, show a Web page in a browser, and communicate with the enclosing Web page using JavaScript when running in a browser.

The javafx.application.HostServices class declares the following methods:

  • String getCodeBase(): Get the code base URI for this application. If the application was launched via a JNLP file, this method returns the codebase parameter specified in the JNLP file. If the application was launched in standalone mode, this method returns the directory containing the application JAR file. If the application is not packaged in a JAR file, this method returns the empty string.
  • String getDocumentBase(): Get the document base URI for this application. If the application is embedded in a browser, this method returns the URI of the Web page containing the application. If the application was launched in WebStart mode, this method returns the the codebase parameter specified in the JNLP file (the document base and the code base are the same in this mode). If the application was launched in standalone mode, this method returns the URI of the current directory.
  • JSObject getWebContext(): Return the JavaScript handle of the enclosing DOM window of the Web page containing this application. This handle is used to access the Web page by calling from Java into JavaScript. If the application is not embedded in a Web page, this method returns null.
  • String resolveURI(String base, String rel): Resolve the specified relative URI against the base URI and return the resolved URI. This method throws java.lang.NullPointerException when either the base or the rel strings are null. It throws java.lang.IllegalArgumentException when there is an error parsing either the base or rel URI strings, or when there is any other error in resolving the URI.
  • void showDocument(String uri): Open the specified URI in a new browser window or tab. The determination of whether it is a new browser window or a tab in an existing browser window will be made by the browser preferences. Note that this will respect the pop-up blocker settings of the default browser; it will not try to circumvent them.

Listing 3 presents a simple JavaFX application that demonstrates most of these methods.

Listing 3. HostServ.java

import javafx.application.Application;
import javafx.application.HostServices;
import javafx.application.Platform;

import javafx.stage.Stage;

public class HostServ extends Application
{
   @Override
   public void start(Stage primaryStage)
   {
      HostServices hs = getHostServices();
      System.out.printf("Code base: %s%n", hs.getCodeBase());
      System.out.printf("Document base: %s%n", hs.getDocumentBase());
      System.out.printf("Web context: %s%n", hs.getWebContext());
      Platform.exit();
   }
}

Compile Listing 3 as follows:

javac HostServ.java

Run the resulting HostServ.class as follows:

java HostServ

You should observe something similar to the following output:

Code base: 
Document base: file:/C:/cpw/javaqa/article19/code/HostServ/
Web context: null

Launching a standalone application

A JavaFX application doesn't require a main() method. The JavaFX runtime takes care of launching the application and saving command-line arguments. However, if you need to perform various tasks before the application is launched, you can specify a main() method and have it invoke one of the following static methods:

  • void launch(Class<? extends Application> appClass, String... args): Launch a standalone application, where appClass identifies the class that's constructed and executed by the launcher, and args identifies the command-line arguments that are passed to the application. This method doesn't return until the application has exited, either via Platform.exit() or by all of the application windows having been closed. It throws java.lang.IllegalStateException when invoked more than once, and throws IllegalArgumentException when appClass doesn't subclass Application.
  • void launch(String... args): Launch a standalone application. This method is equivalent to invoking the previous method with the Class object of the immediately enclosing class of the method that called launch().

Listing 4 presents a simple JavaFX application that demonstrates the second launch() method.

Listing 4. Launch.java

import javafx.application.Application;
import javafx.application.Platform;

import javafx.stage.Stage;

public class Launch extends Application
{
   @Override
   public void start(Stage primaryStage)
   {
      System.out.printf("start() called on %s%n", Thread.currentThread());
      Platform.exit();
   }

   public static void main(String[] args)
   {
      System.out.printf("main() called on %s%n", Thread.currentThread());
      Application.launch(args);
      System.out.printf("terminating");
   }
}

Compile Listing 4 as follows:

javac Launch.java

Run the resulting Launch.class as follows:

java Launch

You should observe the following output:

main() called on Thread[main,5,main]
start() called on Thread[JavaFX Application Thread,5,main]
terminating
1 2 Page 1
Page 1 of 2
InfoWorld Technology of the Year Awards 2023. Now open for entries!