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
'sinit()
method does nothing.void start(Stage primaryStage)
: Start an application. An application must override this abstract method to provide the application's entry point. TheprimaryStage
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
'sstop()
method does nothing.
The JavaFX runtime interacts with an application and invokes these methods in the following order:
- Create an instance of the class that extends
Application
. - Invoke
init()
on the JavaFX Launcher Thread. Becauseinit()
isn't invoked on the JavaFX Application Thread, it must not createjavafx.scene.Scene
orjavafx.stage.Stage
objects, but may create other JavaFX objects. - Invoke
start()
on the JavaFX Application Thread afterinit()
returns and the JavaFX runtime is ready for the JavaFX application to begin running. - Wait for the application to finish. The application ends when it invokes
javafx.application.Platform.exit()
or when the last window has been closed andPlatform
'simplicitExit
attribute is set totrue
. - 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 returnsnull
.String resolveURI(String base, String rel)
: Resolve the specifiedrel
ative URI against thebase
URI and return the resolved URI. This method throwsjava.lang.NullPointerException
when either thebase
or therel
strings arenull
. It throwsjava.lang.IllegalArgumentException
when there is an error parsing either thebase
orrel
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, whereappClass
identifies the class that's constructed and executed by the launcher, andargs
identifies the command-line arguments that are passed to the application. This method doesn't return until the application has exited, either viaPlatform.exit()
or by all of the application windows having been closed. It throwsjava.lang.IllegalStateException
when invoked more than once, and throwsIllegalArgumentException
whenappClass
doesn't subclassApplication
.void launch(String... args)
: Launch a standalone application. This method is equivalent to invoking the previous method with theClass
object of the immediately enclosing class of the method that calledlaunch()
.
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