JDK-8090585 : Provide an official API to start the JavaFX platform
  • Type: Enhancement
  • Component: javafx
  • Sub-Component: application-lifecycle
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2015-02-19
  • Updated: 2017-05-18
  • Resolved: 2015-11-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
At the moment the only way to start the JavaFX platform/toolkit/main-thread is to either have an Application instance around or to call into the internal API, PlatformImpl.start(Runnable).

Providing an official API to start it would be very useful, as it would allow to gain fine-grained control of the JavaFX lifecycle. Having an Application instance around has drawbacks as, for example, Application.launch() will halt the thread it was invoked on. And calling the internal API isn't optimal for (hopefully) obvious reasons.

For example applications could decide to launch JavaFX dynamically if needed, as it is with migrating from one UI toolkit to another the case. The exact use-case is framework development with a framework that does not necessary have one main window, but can have multiple (or none). Having an official way to launch JavaFX without resorting to "hammering Application into the concept" or using the internal API would be great.
Comments
http://hg.openjdk.java.net/openjfx/9-dev/rt/rev/dbf7eaf50391
24-11-2015

I filed JDK-8143968 as a follow-up issue to consider making the internal PlatformImpl.startup method also throw ISE if the platform is also running (which would mean that some internal callers of that code would need to be modified).
24-11-2015

+1 looks good.
22-11-2015

I added a comment to JDK-8090889 (which I closed as "Won't fix") suggesting that part of that RFE was still worth doing: 1) Allow Platform.runLater() to be called before Platform.startup() has finished. We should provide the ability for an application to call Platform.runLater as soon as Platform.startup returns, with the guarantee that the Runnable passed to startup will run before any Runnable passed to a subsequent call to runLater. This would allow code to call Platform.startup() on a background thread without having to worry about what point it is then OK to call runLater. We can either add this as part of this RFE or file a new RFE and do it as a follow-on. Either way, it should be done for JDK 9.
21-11-2015

Webrev for proposed API change with unit tests: http://cr.openjdk.java.net/~kcr/8090585/webrev.00/
20-11-2015

We will need new system level unit tests for this (e.g., additional life-cycle tests).
12-11-2015

The implementation of startup is no longer thread-safe. I suggest something more like the following, which flips the two startup methods, having the one-arg version call the two-arg version so the preventDuplicateCalls check can be done in a thread-safe manner. public static void startup(final Runnable r) { startup(r, false); } /** * This method is invoked typically on the main thread. At this point, * the JavaFX Application Thread has not been started. If preventDuplicateCalls * is true, calling this method multiple times will result in an * IllegalStateException. If it is false, calling this method multiple times * will result in all subsequent calls turning into * nothing more than a runLater call with the provided Runnable being called. * @param r */ public static void startup(final Runnable r, boolean preventDuplicateCalls) { // NOTE: if we ever support re-launching an application and/or // launching a second application in the same VM/classloader ... if (initialized.getAndSet(true)) { if (preventDuplicateCalls) { throw new IllegalStateException("Toolkit already initialized"); }
12-11-2015

The API looks good. Here are some minor javadoc diffs (they are delta diffs from your patch). diff --git a/modules/graphics/src/main/java/javafx/application/Platform.java b/modules/graphics/src/main/java/javafx/application/Platform.java --- a/modules/graphics/src/main/java/javafx/application/Platform.java +++ b/modules/graphics/src/main/java/javafx/application/Platform.java @@ -48,13 +48,21 @@ * runtime, there is not yet any JavaFX Application Thread, so it is normal * that this method is called directly on the main thread of the application. * + * <p> + * This method may or may not return to the caller before the run method + * of the specified Runnable has been called. In any case, once this method + * returns, you may call {@link #runLater} with additional Runnables. + * Those Runnables will be called after the Runnable passed into this method + * has been called. + * </p> + * * <p>As noted, it is normally the case that the JavaFX Application Thread * is started automatically. It is important that this method only be called * when the JavaFX runtime has not yet been initialized. Situations where * the JavaFX runtime is started automatically include: * * <ul> - * <li>Standard JavaFX applications that extend {@see Application}, and + * <li>For standard JavaFX applications that extend {@link Application}, and * use either the Java launcher or one of the launch methods in the * Application class to launch the application, the FX runtime is * initialized automatically by the launcher before the Application @@ -71,14 +79,15 @@ * then it becomes the responsibility of the developer to manually start the * JavaFX runtime by calling this startup method. * - * <p>Calling this method more than once will result in an + * <p>Calling this method when the JavaFX runtime is already running will result in an * {@link IllegalStateException} being thrown - it is only valid to request * that the JavaFX runtime be started once. * - * @throws IllegalStateException If called more than once. + * @throws IllegalStateException if the JavaFX runtime is already running * * @param runnable the Runnable whose run method will be executed on the * JavaFX Application Thread once it has been started. + * * @since 9 */ public static void startup(Runnable runnable) {
12-11-2015

Yes, the fact that it requires a reference to Swing makes it a less-than-ideal workaround for you. I think we will want to provide this in JDK 9, since with the work for the modular JDK you will no longer be able to access com.sun.javafx.application.PlatformImpl.
21-02-2015

Of course, that's actually how I learned about PlatformImpl.startup(Runnable) in the first place (and I left it out because that's what happens in JFXPanel). But I feel obliged to point out that that needs a reference to Swing, which might or might not be desirable depending on the usecase. But you're right, yes, and we obviously agree.
19-02-2015

Minor correction to the above description: There are two supported ways to start the JavaFX runtime. 1) Call Application.launch with a subclass of Application 2) Create a JFXPanel instance. The FX runtime is documented to start the first time such an instance is created. Your request is still valid and something we might consider for a future release of the JavaFX API, but I just wanted to point out that the following is a perfectly fine way to initialize JavaFX: Platform.setImplicitExit(false); new JFXPanel();
19-02-2015