代码之家  ›  专栏  ›  技术社区  ›  CorellianAle

为什么javafx忽略main的返回而仍然启动应用程序?

  •  0
  • CorellianAle  · 技术社区  · 6 年前

    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);
    }
    

    loadConfiguration loadCompany loadRepository

    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;
        }
    }
    

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

    1 回复  |  直到 6 年前
        1
  •  1
  •   Community miroxlav    4 年前

    从你打电话的方式 launch(args) 我想是吧,你以后呢 confirmed 这个,那个 main 方法位于的子类中 Application . 我相信这就是你问题的原因。

    正如您所注意到的,有许多看似特定于JavaFX的线程正在运行。具体来说,非守护进程“JavaFX应用程序线程”正在运行(至少在java10中是非守护进程)。此线程将导致JVM保持活动状态,即使 主要的 线程退出。这是Java的正常行为:

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

    • exit 分类方法 Runtime 已调用,并且安全管理器已允许执行退出操作。
    • run 运行 方法。

    Application.launch 现在呢?我只是在猜测,但这可能与JavaFX应用程序所接受的特殊处理有关。因为至少Java8不需要声明 主要的 应用 1 . 如果主类是 应用 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...
        }
    
    }
    

    然后 主要的 开始 . 基本上,明确声明 主要的 但并不阻止JavaFX运行时被初始化 . 也许这种行为是故意的,也许是疏忽。但重要的是,只有当主类有 主要的 应用 子类。如果你把这两个分开:

    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()


    还有另一种,也许更合适的方法来处理这个问题。你好像在执行初始化 调用前的方法 Application.init() .

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

    注意:JavaFX应用程序线程上不调用此方法。应用程序不能在此方法中构造场景或阶段。应用程序可以在此方法中构造其他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.
             */
        }
    
    }
    

    1JavaFX包含在JavaSE的第8版中。注意,由于JavaFX将再次与javase分离,java11中的这种行为可能会改变。