JavaFX Preloader Thread

时间:2017-04-21 20:36:48

标签: javafx preloader

我需要有人解释一下Preloader在JavaFX应用程序中的工作原理。我已经发现了生命周期,我知道首先调用preloader的start(..)然后启动(..)Application,但是这两个方法是从同一个Thread调用的吗?我试图在应用程序的启动方法中创建一个简单的应用程序,放入Thread.sleep(8000),并在Preloader的开头我创建了一个简单的阶段并显示它。但是当我运行应用程序时,它只是在黑色阶段冻结,并且仅在8秒后正确显示预加载器阶段,但为什么?

使用源代码更新我的帖子:

public class PreloaderApp扩展Preloader {

public void init(){
    System.out.println("Thread Preloader ID:"+ Thread.currentThread().getId());
    System.out.println("  ------  ");

    Pane effectRegion = LoaderFrame.getInstance().getEffectPane();
    JFXFillTransition fill = new JFXFillTransition();
    fill.setDuration(Duration.millis(400));
    fill.setRegion(effectRegion);
    fill.setAutoReverse(true);
    fill.setCycleCount(Animation.INDEFINITE);
    fill.setFromValue(Color.WHITE);
    fill.setToValue(Color.rgb(0,77,147));

    fill.play();

}

@Override
public void start(Stage primaryStage){
    System.out.println("Thread Preloader(start) ID:"+ Thread.currentThread().getId());
    System.out.println("  ------  ");
    LoaderFrame.getInstance().show();

}

}

public class LoaderFrame extends Stage {

private static final LoaderFrame instance = new LoaderFrame();

public static LoaderFrame getInstance(){
    return instance;
}


private Scene scene;
private AnchorPane root;
private BorderPane wraper;
private StackPane effectPane;

private JFXButton loaderPathButton;


public LoaderFrame(){
    initScene();
    this.initStyle(StageStyle.TRANSPARENT);
    this.getIcons().add(new Image("file:imgs/favico/icon48.png"));
}

public void initScene(){
    FXMLLoader loader = new FXMLLoader(Main.class.getResource("xml/loader_frame.fxml"));
    root = null;

    try {
        root = loader.load();
        wraper = (BorderPane) root.lookup("#rootPane");
        loaderPathButton = (JFXButton) root.lookup("#loaderPathButton");
        effectPane = (StackPane) root.lookup("#effectPane");
        scene = new Scene(root);
        scene.setFill(Color.TRANSPARENT);
        scene.getStylesheets().add("file:css/loader.css");
        this.setScene(scene);
    } catch (IOException e) {
        e.printStackTrace();
    }

}


public Pane getEffectPane(){
    return effectPane;
}

}

1 个答案:

答案 0 :(得分:0)

要调查Preloader生命周期,您可以将以下行添加到Preloader类:

    @Override
    public void handleStateChangeNotification(StateChangeNotification info) {
        System.out.println("state: " + info.getType());
    }

Application课程中,您可以在System.out.prinln / init方法中添加start条消息。这会显示Preloader正在运行其不同的状态:BEFORE_LOADBEFORE_INITBEFORE_START

Preloaders start method上调用JavaFXThread时,您必须将来电包裹在Thread.sleep中的Platform.runlater

  

请注意,预加载器遵循与其他JavaFX应用程序相同的规则,包括FX线程规则。特别是,类构造函数和init()方法将在非FX线程上调用,start()将在FX应用程序线程上执行。这也意味着应用程序构造函数/ init()将与preloader start()同时运行。

如果您需要花费一些时间进行初始化,则应该在Apps init方法中执行此操作。当Preloader state更改为BEFORE_START后,您可以隐藏Preloader stage

public class App extends Application {

    private static final int PRELOADER_SHOWTIME_MILLIS = 2000;

    @Override
    public void init() throws Exception {
        long start = System.currentTimeMillis();

        // time consuming initializations

        long duration = System.currentTimeMillis() - start;
        long remainingShowTime = PRELOADER_SHOWTIME_MILLIS - duration;

        if(remaingShowTime > 0 ){
            Thread.sleep(remainingShowTime);
        }
    }

    @Override
    public void start(Stage primaryStage) {
        StackPane root = new StackPane(new Label("application"));
        Scene scene = new Scene(root, 400, 400);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

public class TestPreloader extends Preloader {

    private Stage stage;  

    @Override
    public void start(Stage primaryStage) throws Exception {
        stage = primaryStage;

        Rectangle rect = new Rectangle(200, 200, Color.RED);
        FadeTransition transition = new FadeTransition(Duration.seconds(2), rect);
        transition.setFromValue(0);
        transition.setToValue(1);

        Label lbl = new Label("preloader");
        StackPane root = new StackPane(rect, lbl);

        primaryStage.setScene(new Scene(root));
        primaryStage.show();

        transition.play();
    }

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

}

public class Main {

    public static void main(String[] args) {
        LauncherImpl.launchApplication(App.class, TestPreloader.class, args);
    }

}