【问题标题】:JavaFX Application (that uses a preloaded) exits prematurelyJavaFX 应用程序(使用预加载)过早退出
【发布时间】:2017-05-20 15:18:16
【问题描述】:

我有一个使用预加载器进行初始化的 Java 应用程序。一旦 Preloader 隐藏,主应用程序就会启动并成功加载资源。应用程序窗口随后会短暂加载,然后退出,不会引发任何异常。

主要应用代码:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.adrian.mobsters.gui;

import com.adrian.mobsters.resource.Resource;
import com.adrian.mobsters.resource.ResourceFactory;
import java.io.IOException;
import java.util.logging.Level;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.application.Preloader.ProgressNotification;
import javafx.application.Preloader.StateChangeNotification;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 *
 * @author aelder
 */
public class MainGUI extends Application {

    BooleanProperty ready = new SimpleBooleanProperty(false);

    public void loadResources() {
        Task task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                java.util.logging.Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
                System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog");

                double index = 0;
                for (ResourceFactory factory : ResourceFactory.values()) {
                    index++;
                    Resource resource = factory.getResource();

                    if (resource != null) {
                        resource.importResources();
                        notifyPreloader(new ProgressNotification(((double) index)/ResourceFactory.values().length));
                    }
                }

                ready.setValue(Boolean.TRUE);
                notifyPreloader(new StateChangeNotification(
                        StateChangeNotification.Type.BEFORE_START));
                return null;
            }
        };

        new Thread(task).start();
    }

    @Override
    public void start(Stage primaryStage) throws IOException {  
        loadResources();
        Parent root = FXMLLoader.load(MainGUI.class.getResource("main.fxml"));
        Scene scene = new Scene(root);

        primaryStage.setTitle("Mobsters Bot 2.0 - by Adrian Elder");
        primaryStage.setScene(scene);

        // After the app is ready, show the stage
        ready.addListener(new ChangeListener<Boolean>(){
            public void changed(
                ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
                    if (Boolean.TRUE.equals(t1)) {
                        Platform.runLater(new Runnable() {
                            public void run() {
                                primaryStage.show();
                            }
                        });
                    }
                }
        });;  
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}

预加载代码:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package resourceloader;

import javafx.application.Preloader;
import javafx.application.Preloader.ProgressNotification;
import javafx.application.Preloader.StateChangeNotification;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

/**
 * Simple Preloader Using the ProgressBar Control
 *
 * @author aelder
 */
public class ResourceLoader extends Preloader {

    ProgressBar bar;
    Stage stage;

    private Scene createPreloaderScene() {
        bar = new ProgressBar();
        BorderPane p = new BorderPane();
        p.setCenter(bar);
        return new Scene(p, 300, 150);      
    }

    @Override
    public void start(Stage stage) throws Exception {
        this.stage = stage;
        stage.setScene(createPreloaderScene());     
        stage.show();
    }

    @Override
    public void handleStateChangeNotification(StateChangeNotification scn) {
        if (scn.getType() == StateChangeNotification.Type.BEFORE_START) {
            stage.hide();
        }
    }

    @Override
    public void handleProgressNotification(ProgressNotification pn) {
        bar.setProgress(pn.getProgress());
    }   
}

更新: 似乎与在 runLater 方法中执行 Stage show() 方法有关。由于某种原因,这会导致应用程序过早退出。

我目前的解决方案是休眠直到资源加载完毕,然后在应用线程上执行 show 方法。

public void start(Stage primaryStage) throws IOException {
    this.primaryStage = primaryStage;

    primaryStage.setTitle("Mobsters Bot 2.0 - by Adrian Elder");
    primaryStage.getIcons().add(new Image(MainGUI.class.getResourceAsStream("/icons/sword.png")));

    currentThread = Thread.currentThread();
    primaryStage.setScene(new Scene(parent.get()));
    primaryStage.show();
}

@Override
public void init() throws InterruptedException {
    // After the app is ready, show the stage
    loadResources();

    while(!ready.get()) {
        Thread.sleep(100);
    }
}

【问题讨论】:

    标签: java javafx preloader


    【解决方案1】:

    将您的primaryStage.show(); 移出事件并将其放在primaryStage.setScene(scene); 之后,然后查看应用程序是否正常打开。我认为问题在于将其标记为就绪的事件

    这对我有用.. 尝试评论记录器和资源,然后取消部分评论.. 这将有助于调试。因为我没有你的图书馆,所以我不能做更多。

    public class Main extends Application {
    
        BooleanProperty ready = new SimpleBooleanProperty(false);
    
        public void loadResources() {
            Task task = new Task<Void>() {
    
                @Override
                protected Void call() throws Exception {
                    //java.util.logging.Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
                    //System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog");
    
                    /*double index = 0;
                    for (ResourceFactory factory : ResourceFactory.values()) {
                        index++;
                        Resource resource = factory.getResource();
    
                        if (resource != null) {
                            resource.importResources();
                            notifyPreloader(new ProgressNotification(((double) index) / ResourceFactory.values().length));
                        }
                    }*/
    
                    ready.setValue(Boolean.TRUE);
                    notifyPreloader(new StateChangeNotification(StateChangeNotification.Type.BEFORE_START));
                    return null;
                }
            };
    
            new Thread(task).start();
        }
    
        @Override
        public void start(Stage primaryStage) throws IOException {
    
            //Parent root = FXMLLoader.load(Main.class.getResource("main.fxml"));
            Scene scene = new Scene(new Label("Application started"), 400, 400);
    
            primaryStage.setTitle("Mobsters Bot 2.0 - by Adrian Elder");
            primaryStage.setScene(scene);
    
            // After the app is ready, show the stage
            ready.addListener(new ChangeListener<Boolean>() {
                public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
                    if (Boolean.TRUE.equals(t1)) {
                        Platform.runLater(new Runnable() {
                            public void run() {
                                primaryStage.show();
                            }
                        });
                    }
                }
            });
            loadResources();
        }
    
        /**
         * @param args
         *            the command line arguments
         */
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    【讨论】:

    • 这解决了问题,但这不会允许应用程序在资源加载完成之前启动吗?我按照oracle的教程(图13-12)(docs.oracle.com/javase/8/docs/technotes/guides/deploy/…)使用了这个事件模式。
    • 我认为问题在于您受保护的 Void call() 抛出异常函数。你调试了吗?我认为在该函数中添加一个try catch,你应该会得到一个错误。我无法调试您的代码,因为它引用了一些我没有的库
    • 即使删除了我的所有本机代码,该错误仍然会发生。删除除将进度条通知更新为 1.0 之外的所有代码。
    • 我的 JDK 一定有问题什么的...我使用了你的代码,但它仍然没有运行。
    • 嗯。可能是...我使用的是 1.8 jdk,默认情况下带有 jfx 库
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多