JavaFX程序何时调用start方法?

时间:2014-05-19 04:26:56

标签: java javafx

我正在学习JavaFX。我只能在main方法中看到启动(args)方法。当我调试进入发布时。我看不到任何语句调用start()。那么JavaFX程序何时调用start方法? 这是launch(args)源代码。

    public static void launch(String... args) {
    // Figure out the right class to call
    StackTraceElement[] cause = Thread.currentThread().getStackTrace();

    boolean foundThisMethod = false;
    String callingClassName = null;
    for (StackTraceElement se : cause) {
        // Skip entries until we get to the entry for this class
        String className = se.getClassName();
        String methodName = se.getMethodName();
        if (foundThisMethod) {
            callingClassName = className;
            break;
        } else if (Application.class.getName().equals(className)
                && "launch".equals(methodName)) {

            foundThisMethod = true;
        }
    }

    if (callingClassName == null) {
        throw new RuntimeException("Error: unable to determine Application class");
    }

    try {
        Class theClass = Class.forName(callingClassName, true,
                           Thread.currentThread().getContextClassLoader());
        if (Application.class.isAssignableFrom(theClass)) {
            Class<? extends Application> appClass = theClass;
            LauncherImpl.launchApplication(appClass, args);
        } else {
            throw new RuntimeException("Error: " + theClass
                    + " is not a subclass of javafx.application.Application");
        }
    } catch (RuntimeException ex) {
        throw ex;
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

5 个答案:

答案 0 :(得分:7)

LauncherImpl调用Application#start,但是通过PlatformImpl.runAndWait将actuall调用放到JavaFX事件队列中。这是在Preloader启动后完成的

Application#launch调用LauncherImpl.launchApplication,创建Thread并调用launchApplication1launchApplication然后等待此Thread终止,通过CountDownLatch

Thread然后调用LauncherImpl.launchApplication1,根据有关Preloader调用状态{{1}的数量决定,如果指定,则启动Preloader包含在Application#start调用中,以确保在JavaFX的GUI /事件队列线程的上下文中调用runAndWait ...

这基于Java 8

<强>更新...

start调用的

theApp.start是您LauncherImpl.launcherApplication1的实例。

Application通过走Application ...所有事情来查找您的班级名称......

StackTrace

这会获取您的类的名称,然后使用StackTraceElement[] cause = Thread.currentThread().getStackTrace(); boolean foundThisMethod = false; String callingClassName = null; for (StackTraceElement se : cause) { // Skip entries until we get to the entry for this class String className = se.getClassName(); String methodName = se.getMethodName(); if (foundThisMethod) { callingClassName = className; break; } else if (Application.class.getName().equals(className) && "launch".equals(methodName)) { foundThisMethod = true; } } 创建一个Class实例并将其传递给Class.forName ...

然后

LauncherImpl构建此类的新实例并将其分配给引用launcherApplication1,该引用是theApp

的实例
Application

然后它会调用PlatformImpl.runAndWait(new Runnable() { @Override public void run() { try { Constructor<? extends Application> c = appClass.getConstructor(); app.set(c.newInstance()); // Set startup parameters ParametersImpl.registerParameters(app.get(), new ParametersImpl(args)); PlatformImpl.setApplicationName(appClass); } catch (Throwable t) { System.err.println("Exception in Application constructor"); constructorError = t; error = true; } } }); } final Application theApp = app.get(); 来调用theApp.start的{​​{1}}方法....我知道很奇怪,但它就是

答案 1 :(得分:4)

JavaFX程序既不需要main()方法也不需要调用Application.launch()方法。

您可以从应用程序中删除main()方法,java application launcher将直接调用init()(在启动程序线程上)和start()(在JavaFX应用程序线程上) )应用程序的方法。执行此操作时,将跳过某些其他线程中讨论的整个LauncherImpl进程(以及通过StackTrace查找启动的类的奇怪决定)。

请参阅相关的Java Enhancement Proposal JEP 153: "Enhance the java command-line launcher to launch JavaFX applications."及其随附的问题跟踪链接JDK-8001533 "java launcher must launch javafx applications"

当然,如果除main()方法之外还有start()方法,那么代码目前将按照MadProgrammer在其答案中列出的路径进行。

在编写JavaFX程序时,最好假设永远不会调用main()(尽管实际上,如果你没有部署为applet,很可能会调用main()只是为了阻止人们完全糊涂。)

此过程也在Application javadoc

中描述
  

Java启动程序加载并初始化指定的Application   JavaFX应用程序线程上的类。如果没有主要方法   Application类,或者main方法调用   然后是Application.launch(),然后是Application的一个实例   在JavaFX应用程序线程上构建。

答案 2 :(得分:2)

发布时,LauncherImpl的源代码为here,第837行调用start(...)方法。在源代码中,它非常严峻......

答案 3 :(得分:1)

添加到MadProgrammer的答案:

Application.class,第241行:

public static void launch(String... args) {
    //...
        if (Application.class.isAssignableFrom(theClass)) {
            Class<? extends Application> appClass = theClass;
            LauncherImpl.launchApplication(appClass, args); // <-- This is where the application is launched

    //...
}

到这里(LauncherImpl.class的第118行):

public static void launchApplication(final Class<? extends Application> appClass,
        final String[] args) {
    launchApplication(appClass, savedPreloaderClass, args);
}

其中(第158行):

public static void launchApplication(final Class<? extends Application> appClass,
        final Class<? extends Preloader> preloaderClass,
        final String[] args) {
    //.......
    Thread launcherThread = new Thread(new Runnable() {
        @Override public void run() {
            try {
                launchApplication1(appClass, preloaderClass, args); // <-- go here
            } catch (RuntimeException rte) {
    //....
}

第674行的loooong方法:

private static void launchApplication1(final Class<? extends Application> appClass,
        final Class<? extends Preloader> preloaderClass,
        final String[] args) throws Exception {
    //... Lots of stuff 
    // Eventually, on line 755:
    currentPreloader.start(primaryStage);

    // More things for cases where the previous start() call isn't appropriate
    // Line 773:
    final AtomicReference<Application> app = new AtomicReference<>();
    // Line 790/791:
    Constructor<? extends Application> c = appClass.getConstructor(); // Gets constructor for your class
    app.set(c.newInstance()); // Creates a new instance of your class
    // Line 803:
    final Application theApp = app.get();
    // Line 837:
    theApp.start(primaryStage);
}

因为您的JavaFX项目扩展ApplicationappClass 成为JavaFX项目的类对象,因此将调用您定义的start()方法按theApp.start()

已经删除了很多东西,因为源很多太长而无法在此处发布,但这是基本的调用链

答案 4 :(得分:0)

也只是学习JavaFx,我觉得它刚刚用你的类初始化,因为它是你主要参数之上的方法。我目前正在使用一个只包含主参数和start方法的简单类,没有其他命令,并且start方法似乎在编译时执行,但是应该在

上调用
launch(args);

这是我的主要参数的全部内容,这就是为我执行start方法的方法