在 JavaFX 中,我猜为了防止在许多 Swing 应用程序中出现的非常常见的线程错误,启动过程受到限制,因此(或多或少)唯一的做事方式迫使您执行FX 应用线程上的 UI 代码:
public class MyAppStartClass extends Application {
@Override
public void start(Stage primaryStage) {
// this method will be executed on the FX Application Thread
// load UI and display it here....
}
}
在 Oracle JRE 中,执行 java MyAppStartClass 将(与常规 Java 应用程序相反)导致创建 MyAppStartClass 的实例,启动 FX 应用程序线程,以及 start 的方法创建要在 FX 应用程序线程上执行的实例。 (除此之外还有更多内容,但这是基本要点。)
如果您想支持不知道如何执行 JavaFX 应用程序的环境(包括许多 IDE),您可以添加一个 main 方法来强制执行此操作,只需调用静态 Application.launch() 方法:
public class MyAppStartClass extends Application {
@Override
public void start(Stage primaryStage) {
// this method will be executed on the FX Application Thread
// load UI and display it here....
}
// to support non-JavaFX-aware environments:
public static void main(String[] args) {
launch(args);
}
}
请注意launch 的重载形式,您可以在其中指定Application 子类,因此您可以拥有不同的主类(用例很少):
public class MainClass {
public static void main(String[] args) {
Application.launch(MyAppStartClass.class, args);
}
}
launch 方法有两个重要特性需要注意:
- 每个 JVM 生命周期只能调用一次。再次调用它会引发异常。
- 它会一直阻塞,直到 JavaFX 平台退出。
如果你想让一个线程在FX Application Thread之外工作,最简单的方法是直接从start方法启动它:
public class MyAppStartClass extends Application {
@Override
public void start(Stage primaryStage) {
// start a background thread to do background stuff:
new Thread(() -> {
// background work...
}).start();
// UI work...
}
}
如果您将此与 Swing 应用程序的标准启动进行比较:
public class MySwingApp {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// UI work...
});
// background work...
}
}
与 Swing 相比,该过程有点颠倒。在 Swing 中,您(应该)显式地让启动方法(main)指定 UI 在 AWT 事件调度线程上运行,并且您可以在执行 main 的“当前”线程中执行其他操作。在 JavaFX 中,启动方法 (start) 在 UI 线程上执行,如果您想在另一个线程上执行操作,则显式启动一个。
其他规则几乎相同:作为场景图一部分的 UI 元素只能在 UI 线程上进行修改等。注意 JavaFX 有一个特定的concurrency API 用于在后台线程中管理任务和调度 UI 更新在 FX 应用程序线程上。
旁白:
理论上我想你可以这样做:
public class MainClass {
public static void main(String[] args) {
new Thread(() -> Application.launch(MyAppStartClass.class, args)).start();
// do "background thread" work here in the (now free) main thread
}
}
但由于该成语与通常的设置相去甚远,因此我不推荐它。请特别注意,您不应该直接在 Application 子类中使用这样的 main 方法,因为(我认为)Oracle JRE(或知道如何运行 JavaFX 应用程序的环境)可能会忽略 main 方法并启动您的启动方法如本文顶部所述。