如何从主应用程序的init()方法调用JavaFX应用程序's预加载器实例中的方法?



在JavaFX应用程序的init()方法中,我正在做一些检查,其中之一是检查它是否可以连接到基于Http响应代码的web地址。这个应用程序也有一个预加载程序,在这些检查发生时运行。

根据响应代码,我希望它在预加载器应用程序的生命周期内显示一个警告窗口

我不确定这是否可能使用当前javafx预加载器类,但是是否有任何解决方案可以实现这一点?

下面是我想要的SSCCE

应用程序
public class MainApplicationLauncher extends Application implements Initializable{
...
public void init() throws Exception {       

for (int i = 1; i <= COUNT_LIMIT; i++) {
double progress =(double) i/10;
System.out.println("progress: " +  progress);         

notifyPreloader(new ProgressNotification(progress));
Thread.sleep(500);
}

try {
URL url = new URL("https://example.com");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.connect();           
int code = connection.getResponseCode();
System.out.println("Response code of the object is "+code);
if (code==200) {
System.out.println("Connected to the internet!");
}else if (code==503){
//call the handleConnectionWarning() in preloader
System.out.println("server down !");
}
} catch (UnknownHostException e) {
//call the handleConnectionWarning() in preloader
System.out.println("cannot connect to the internet!");
}
public static void main(String[] args) {        
System.setProperty("javafx.preloader", MainPreloader.class.getCanonicalName());
Application.launch(MainApplicationLauncher.class, args);
}
}

preloader

public class MyPreloader extends Preloader {
...
//Method that should be called from application method
public void handleConnectionWarning() {
Alert alert = new Alert(AlertType.WARNING);
alert.setTitle("Server is Offline");
alert.setHeaderText("Cannot connect to service");
alert.setContentText("Please check your connection");
alert.showAndWait();
}
}

有什么办法可以做到吗?

Preloader

如果您想继续使用Preloader作为启动屏幕,那么您可以通过通知调用所需的方法。创建您自己的通知类:

// You can modify this class to carry information to the Preloader, such
// as a message indicating what kind of failure occurred.
public class ConnectionFailedNotification implements Preloader.PreloaderNotification {}

发送给你的Preloader:

notifyPreloader(new ConnectionFailedNotification());

并在上面的Preloader中处理:

@Override
public void handleApplicationNotification(PreloaderNotification info) {
if (info instanceof ConnectionFailedNotification) {
handleConnectionWarning();
}
// ...
}

没有预紧器

当您通过Java Web Start(即Web浏览器)部署应用程序时,Preloader类更有意义,其中代码必须在使用之前下载。但是不再支持Java Web Start(尽管我认为可能有第三方至少维护类似的东西)。考虑到应用程序的目标可能是简单的桌面部署,使用Preloader可能会使事情变得不必要地复杂。可以考虑在初始化后简单地更新初级阶段的内容。

init()的内容移动到Task的实现中:

import java.io.IOException;
import javafx.concurrent.Task;
public class InitTask extends Task<Void> {
private static final int COUNT_LIMIT = 10;
private final boolean shouldSucceed;
public InitTask(boolean shouldSucceed) {
this.shouldSucceed = shouldSucceed;
}
@Override
protected Void call() throws Exception {
for (int i = 1; i <= COUNT_LIMIT; i++) {
updateProgress(i, COUNT_LIMIT);
Thread.sleep(500);
}

// could use a Boolean return type for this, but your real code seems
// more complicated than a simple "yes" / "no" response. If you do
// change the implementation to use a return value, note that you would
// then need to check that return value in the 'onSucceeded' handler
if (!shouldSucceed) {
throw new IOException("service unavailable"); // failure
}
return null; // success
}

}

然后在后台线程中启动该任务:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;;
public class App extends Application {

@Override
public void start(Stage primaryStage) throws Exception {
var task = new InitTask(false); // change to 'true' to simulate success
task.setOnSucceeded(e -> primaryStage.getScene().setRoot(createMainScreen()));
task.setOnFailed(e -> {
var alert = new Alert(AlertType.WARNING);
alert.initOwner(primaryStage);
alert.setTitle("Server Offline");
alert.setHeaderText("Cannot connect to service");
alert.setContentText("Please check your connection");
alert.showAndWait();
Platform.exit();
});
// Also see the java.util.concurrent.Executor framework
var thread = new Thread(task, "init-thread");
thread.setDaemon(true);
thread.start();
var scene = new Scene(createSplashScreen(task), 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private StackPane createSplashScreen(InitTask task) {
var bar = new ProgressBar();
bar.progressProperty().bind(task.progressProperty());
return new StackPane(bar);
}
private StackPane createMainScreen() {
return new StackPane(new Label("Hello, World!"));
}
}

Application子类不应该实现Initializable。这个子类代表了整个应用程序,不应该用作FXML控制器。

最新更新