为什么javafx忽略从main返回并仍然启动一个应用程序?

问题描述 投票:0回答:1

我有以下代码。

public static void main(String[] args)
{
    if (!ArgumentsHandler.handle(args))
    {
        return;
    }

    Storage.getInstance().load();

    if (!Storage.getInstance().isLoadSuccessful())
    {
        launch(args);
    }
    else
    {
        System.err.println("Unable to load configurations.");
    }
}

我特意将if语句中的条件转换为失败,我可以在调试器中看到它不执行launch方法,但应用程序窗口仍在显示。

我还注意到在return方法中使用main语句没有效果 - 应用程序仍然继续执行。它只响应System.exit(0)

为什么会这样?

更新:

根据您的要求,这里有一段ArgumentsHandler。我在这里无处使用线程(至少是故意的)。

public static boolean handle(String[] args)
{
    //handle args
    if (args.length > 0)
    {
        switch (args[0])
        {
            //createRepository
            case "-c":
                configure(args);
                break;
            case "-r":
            case "--repository":
                repository(args);
                break;
            default:
                help();
                break;
        }

        return false;
    }

    return true;
}

private static void configure(String[] args)
{
    if (args.length > 1)
    {
        boolean isRandom = false;

        switch (args[1])
        {
            case "true":
            case "1":
                isRandom = true;
                break;
            case "false":
            case "0":
                //valid input, ignored
                break;
            default:
                System.err.println("Invalid arguments. Possible values: [--configuration] [1/0].");
                return;
        }

        Storage.configure(isRandom); //creates a bunch of json files (uses NIO).
        return;
    }
    else
    {
        System.err.println("Invalid arguments. Possible values: -c [1/0].");
    }
}

存储

public void load()
{
    isLoadSuccessful = false;

    //load configuration
    app = loadConfiguration(appFilePath);

    if (app == null)
    {
        System.err.println("Unable to load app configuration.");
        return;
    }

    //load company
    company = loadCompany(app.getCompanyFilePath());

    if (company == null)
    {
        System.err.println("Unable to load company configuration.");
        return;
    }

    repository = loadRepository(app.getRepositoryFilePath());

    if (repository == null)
    {
        System.err.println("Unable to load repository configuration.");
        return;
    }

    isLoadSuccessful = true;
}

private static App loadConfiguration(String filePath)
{
    return (App) Utility.load(filePath, App.class);
}

loadConfigurationloadCompanyloadRepository真的是一样的。将来,他们不会阅读简单的json文件,但会访问复杂的档案,这就是为什么我已经创建了几个几乎相同的方法。

Utility.load

public static Object load(String path, Type type)
{
    try
    {
        JsonReader reader = new JsonReader(new FileReader(path));
        Gson gson = new Gson();
        Object obj = gson.fromJson(reader, type);
        reader.close();

        return obj;
    }
    catch (IOException ex)
    {
        ex.printStackTrace();
        return null;
    }
}

只是从文件反序列化对象。

java javafx return main
1个回答
1
投票

从你调用launch(args)的方式我假设,你后来confirmed这个,main方法是在Application的子类。我相信这是你问题的原因。

正如您所指出的那样,有许多看似特定于JavaFX的线程正在运行。具体来说,非守护进程“JavaFX Application Thread”正在运行(至少,它是Java 10中的非守护进程)。即使main线程退出,该线程也会使JVM保持活动状态。这是Java的正常行为:

java.lang.Thread中

当Java虚拟机启动时,通常会有一个非守护进程线程(通常调用某个指定类的名为main的方法)。 Java虚拟机继续执行线程,直到发生以下任一情况:

  • 已经调用了exit类的Runtime方法,并且安全管理器允许进行退出操作。
  • 通过调用run方法返回或抛出传播超出run方法的异常,所有非守护程序线程的线程都已死亡。

但是,当你故意不调用Application.launch时,为什么会启动“JavaFX应用程序线程”呢?我只是在这里猜测,但它可能与JavaFX应用程序接收的特殊处理有关。至少从Java 8开始,你不必在main1的子类中声明一个Application方法。如果主类是Application的子类,Java会自动处理启动。

import javafx.application.Application;
import javafx.stage.Stage;

public class MyApp extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        // create scene and show stage...
    }

}

如果你有上述内容并调用java MyApp,应用程序将启动并调用start。但是,如果您有以下内容:

import javafx.application.Application;
import javafx.stage.Stage;

public class MyApp extends Application {

    public static void main(String[] args) {}

    @Override
    public void start(Stage primaryStage) throws Exception {
        // create scene and show stage...
    }

}

然后调用main方法,但start不是。基本上,显式声明main会覆盖启动JavaFX应用程序的默认行为,但不会停止JavaFX运行时的初始化。也许这种行为是设计的,也许是疏忽。但重要的是,只有当主类具有main方法并且是Application子类时才会发生这种情况。如果你将这两者分开:

public class MyApp extends Application {
    // implement ...
}

public class Main {
    public static void main(String[] args) {
        // Perform pre-checks, return if necessary
        Application.launch(MyApp.class, args);
    }
}

然后你将不再有这个问题。

否则你可以继续使用System.exit()或切换到Platform.exit()


有另一种,也许更合适的方式来处理这个问题。你似乎在调用main之前在Application.launch方法中执行初始化。如果在初始化期间出现问题,您希望中​​止启动JavaFX应用程序。好吧,JavaFX提供了自己做的方法:Application.init()

应用程序初始化方法。在加载和构造Application类之后立即调用此方法。应用程序可以覆盖此方法以在实际启动应用程序之前执行初始化。

Application类提供的此方法的实现不执行任何操作。

注意:不在JavaFX应用程序线程上调用此方法。应用程序不得在此方法中构造Scene或Stage。应用程序可以在此方法中构造其他JavaFX对象。

将初始化代码移动到此方法。如果你调用Platform.exit(),那么应用程序将退出并且不会调用Application.start。另一种方法是在init中抛出异常。您还可以使用返回Application.getParameters()实例的Application.Parameters来获取应用程序参数。

public class MyApp extends Application {

    @Override
    public void init() throws Exception {
        if (!ArgumentsHandler.handle(getParameters()) {
            Platform.exit(); // or throw an exception
        } else {
            Storage storage = Storage.getInstance();
            storage.load();
            if (!storage.isLoadSuccessful()) {
                Platform.exit(); // or throw an exception
            }
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        // Create Scene and show the primary Stage
    }

    @Override
    public void stop() throws Exception {
        /*
         * Called when the JavaFX application is exiting, such as from
         * a call to Platform.exit(). Note, however, that in my experience
         * this method is *not* called when Platform.exit() is called inside
         * the "init" method. It is called if Platform.exit() is called from
         * inside the "start" method or anywhere else in the application once
         * it is properly started.
         *
         * This is where you could perform any necessary cleanup.
         */
    }

}

1. JavaFX包含在Java SE 8版本中。请注意,Java 11中的此行为可能会发生变化,因为JavaFX将再次与Java SE分离。

© www.soinside.com 2019 - 2024. All rights reserved.