gpt4 book ai didi

java - 如何在预加载器中处理 java web start (jnlp) 下载进度?

转载 作者:IT老高 更新时间:2023-10-28 21:13:09 27 4
gpt4 key购买 nike

问题

我的应用程序有一个预加载器,用于处理特定于应用程序的初始化。现在我正在尝试扩展它,以便预加载器也显示下载的应用程序 JAR 的进度。

TL; 博士

  • 为什么在 期间没有加载预加载器第二阶段 ,因为这应该处理 PreloaderFx::handleProgressNotification();跟踪 JAR 的下载我想?
  • 2016 年 3 月 14 日更新 : 使用 DownloadServiceListener 是解决这个问题的方法吗?如何将其连接到 JavaFX 阶段?


  • 文档

    According to Oracle ,应用程序启动时有 4 个阶段:
  • 第一阶段:初始化 :Java 运行时的初始化和初始检查确定在启动应用程序之前必须加载和执行的组件。
    在此阶段,将显示启动画面。默认是这样的:

  • Java starts
  • 阶段 2:加载和准备 :从网络或磁盘缓存加载所需的资源,并进行验证程序。所有执行模式都可以看到默认的或自定义的预加载器。在此阶段,应显示我的自定义预加载器。
  • 阶段 3:特定于应用程序的初始化 :应用程序已启动,但它可能需要加载额外的资源或执行其他冗长的准备工作才能完全发挥作用。目前,我的自定义预加载器显示为:

  • preloader
  • 阶段 4:应用程序执行 :应用程序已显示并可供使用。在我的例子中,会显示一个登录窗口,用户可以继续。

  • login

    我的情况

    我注意到的第一件事是在 第二阶段 ,处理应用程序 JAR 下载的默认 JavaFX 预加载器未显示。因此,用户会感觉程序没有启动或提前终止,从而导致他们多次打开 JNLP 文件。下载 JAR 后,我们输入 第三阶段 并显示了预加载器。

    但是,我希望我的自定义预加载器也处理 ProgressBar 中的下载进度(第 2 阶段)。我使一切尽可能简单,以跟踪在我的应用程序启动期间发生的事件。这是基于 example of Jewelsea并在 Oracle examples :

    预加载器:
    public class PreloaderFX extends Preloader {

    Stage stage;
    //boolean noLoadingProgress = true;

    public static final String APPLICATION_ICON
    = "http://cdn1.iconfinder.com/data/icons/Copenhagen/PNG/32/people.png";
    public static final String SPLASH_IMAGE
    = "http://fxexperience.com/wp-content/uploads/2010/06/logo.png";

    private Pane splashLayout;
    private ProgressBar loadProgress;
    private Label progressText;
    private static final int SPLASH_WIDTH = 676;
    private static final int SPLASH_HEIGHT = 227;

    @Override
    public void init() {
    ImageView splash = new ImageView(new Image(
    SPLASH_IMAGE
    ));
    loadProgress = new ProgressBar();
    loadProgress.setPrefWidth(SPLASH_WIDTH - 20);
    progressText = new Label("Loading . . .");
    splashLayout = new VBox();
    splashLayout.getChildren().addAll(splash, loadProgress, progressText);
    progressText.setAlignment(Pos.CENTER);
    splashLayout.setStyle(
    "-fx-padding: 5; "
    + "-fx-background-color: white; "
    + "-fx-border-width:5; "
    );
    splashLayout.setEffect(new DropShadow());
    }

    @Override
    public void start(Stage stage) throws Exception {
    System.out.println("PreloaderFx::start();");

    //this.stage = new Stage(StageStyle.DECORATED);
    stage.setTitle("Title");
    stage.getIcons().add(new Image(APPLICATION_ICON));
    stage.initStyle(StageStyle.UNDECORATED);
    final Rectangle2D bounds = Screen.getPrimary().getBounds();
    stage.setScene(new Scene(splashLayout));
    stage.setX(bounds.getMinX() + bounds.getWidth() / 2 - SPLASH_WIDTH / 2);
    stage.setY(bounds.getMinY() + bounds.getHeight() / 2 - SPLASH_HEIGHT / 2);
    stage.show();

    this.stage = stage;
    }

    @Override
    public void handleProgressNotification(ProgressNotification pn) {
    System.out.println("PreloaderFx::handleProgressNotification(); progress = " + pn.getProgress());
    //application loading progress is rescaled to be first 50%
    //Even if there is nothing to load 0% and 100% events can be
    // delivered
    if (pn.getProgress() != 1.0 /*|| !noLoadingProgress*/) {
    loadProgress.setProgress(pn.getProgress() / 2);
    /*if (pn.getProgress() > 0) {
    noLoadingProgress = false;
    }*/
    }
    }

    @Override
    public void handleStateChangeNotification(StateChangeNotification evt) {
    //ignore, hide after application signals it is ready
    System.out.println("PreloaderFx::handleStateChangeNotification(); state = " + evt.getType());
    }

    @Override
    public void handleApplicationNotification(PreloaderNotification pn) {
    if (pn instanceof ProgressNotification) {
    //expect application to send us progress notifications
    //with progress ranging from 0 to 1.0
    double v = ((ProgressNotification) pn).getProgress();
    System.out.println("PreloaderFx::handleApplicationNotification(); progress = " + v);
    //if (!noLoadingProgress) {
    //if we were receiving loading progress notifications
    //then progress is already at 50%.
    //Rescale application progress to start from 50%
    v = 0.5 + v / 2;
    //}
    loadProgress.setProgress(v);
    } else if (pn instanceof StateChangeNotification) {
    System.out.println("PreloaderFx::handleApplicationNotification(); state = " + ((StateChangeNotification) pn).getType());
    //hide after get any state update from application
    stage.hide();
    }
    }
    }

    正在处理的代码 第三阶段 来自与预加载器交互的主应用程序,这是在进度条中看到的:
    public class MainApp extends Application {
    BooleanProperty ready = new SimpleBooleanProperty(false);

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

    @Override
    public void start(final Stage initStage) throws Exception {
    System.out.println("MainApp::start();");
    this.mainStage = initStage;

    longStart();

    ready.addListener((ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) -> {
    if (Boolean.TRUE.equals(t1)) {
    Platform.runLater(() -> {
    System.out.println("MainApp::showMainStage();");
    showMainStage();
    });
    }
    });
    }

    private void longStart() {
    //simulate long init in background
    Task task = new Task<Void>() {
    @Override
    protected Void call() throws Exception {
    int max = 10;
    for (int i = 1; i <= max; i++) {
    Thread.sleep(500);
    System.out.println("longStart " + i);
    // Send progress to preloader
    notifyPreloader(new ProgressNotification(((double) i)/max)); //this moves the progress bar of the preloader
    }
    // After init is ready, the app is ready to be shown
    // Do this before hiding the preloader stage to prevent the
    // app from exiting prematurely
    ready.setValue(Boolean.TRUE);

    notifyPreloader(new StateChangeNotification(
    StateChangeNotification.Type.BEFORE_START));

    return null;
    }
    };
    new Thread(task).start();
    }

    private void showMainStage() {
    //showing the login window
    }
    }

    JNLP
    <jnlp spec="1.0+" xmlns:jfx="http://javafx.com" codebase="<***>/preloadertest/jnlp" href="launch.jnlp">
    <information>
    ...
    </information>
    <resources>
    <j2se version="1.6+" href="http://java.sun.com/products/autodl/j2se" />


    ... //whole bunch of JARS

    <jar href="lib/preloader-1.1.1.jar" download="progress" />


    </resources>
    <security>
    <all-permissions/>
    </security>
    <applet-desc width="1024" height="768" main-class="com.javafx.main.NoJavaFXFallback" name="JavaFX Client">
    <param name="requiredFXVersion" value="8.0+"/>
    </applet-desc>
    <jfx:javafx-desc width="1024" height="768" main-class="GUI.MainApp" name="JavaFX Client" preloader-class="GUI.PreloaderFX" />
    <update check="background"/>
    </jnlp>

    调试

    我在启动文件时仔细观察了 Java 控制台(启用了显示日志记录,禁用了显示跟踪)并注意到以下事情:

    期间 第二阶段 ,Java 控制台中没有任何显示(控制台在此阶段后关闭)

    期间 第三阶段 ,生成以下输出(在新的控制台窗口中):
    PreloaderFx::start();
    PreloaderFx::handleProgressNotification(); progress = 1.0
    PreloaderFx::handleStateChangeNotification(); state = BEFORE_LOAD
    PreloaderFx::handleStateChangeNotification(); state = BEFORE_INIT
    PreloaderFx::handleStateChangeNotification(); state = BEFORE_START
    MainApp::start();
    MainApp::longstart();
    longStart 1
    PreloaderFx::handleApplicationNotification(); progress = 0.1
    longStart 2
    PreloaderFx::handleApplicationNotification(); progress = 0.2
    longStart 3
    PreloaderFx::handleApplicationNotification(); progress = 0.3
    longStart 4
    PreloaderFx::handleApplicationNotification(); progress = 0.4
    longStart 5
    PreloaderFx::handleApplicationNotification(); progress = 0.5
    longStart 6
    PreloaderFx::handleApplicationNotification(); progress = 0.6
    longStart 7
    PreloaderFx::handleApplicationNotification(); progress = 0.7
    longStart 8
    PreloaderFx::handleApplicationNotification(); progress = 0.8
    longStart 9
    PreloaderFx::handleApplicationNotification(); progress = 0.9
    longStart 10
    PreloaderFx::handleApplicationNotification(); progress = 1.0
    MainApp::showMainStage();
    PreloaderFx::handleApplicationNotification(); state = BEFORE_START

    2016 年 3 月 13 日更新:
  • 调整了代码,以便使用方法中传递的阶段,而不是创建一个新阶段,并注释掉与 noLoadingProgress 相关的所有内容。 boolean 值(由 nhylated 建议)
  • 添加了一些额外的 System.out.println()在主应用程序中


  • 解决方案

    简单添加 <jfx:javafx-runtime version="8.0+"/>到 JNLP 文件修复它。添加该行后,预加载器显示在第 2 阶段。我还冒昧地更改了 j2se version="1.6+"j2se version="1.8+"结果:

    Preloader result

    前 50% 是 JAR 下载的处理。这是由 handleProgressNotification() 完成的方法。第二个 50% 是 MainApp 的实际初始化( longstart() 通知预加载器),由 handleApplicationNotification() 完成.

    最佳答案

    我最近也一直在与这个作斗争。我切换回(丑陋的)默认预加载器(因为它显示得很好),直到我找到更多时间对此进行调查。

    如果启用 Java Webstart 完整跟踪

    "<JAVA_HOME>\bin\javaws.exe" -userConfig deployment.trace true
    "<JAVA_HOME>\bin\javaws.exe" -userConfig deployment.trace.level all

    您应该会看到预加载器消息,这些消息应该为您提供有关正在发生的事情的一些信息。就我而言,我可以看到很多这样的消息
    preloader: Added pending event 2: DownloadEvent[type=load,loaded=0, total=62791, percent=0]

    表明自定义预加载器尚未验证/启动,但下载事件已经进入。

    如果切换 <update check="background"/> 会发生什么至 <update check="always"/> ?

    编辑

    这是我的测试 JNLP。似乎您没有指定 JavaFX 运行时资源?
    <?xml version="1.0" encoding="utf-8"?>
    <jnlp spec="1.0+" xmlns:jfx="http://javafx.com" codebase="http://localhost:8080/HelloWorldFX" href="HelloWorldFX.jnlp">
    <information>
    <title>HelloWorldFX</title>
    <vendor>Unknown</vendor>
    <description>HelloWorldFX</description>
    <offline-allowed/>
    </information>
    <resources os="Windows">
    <jfx:javafx-runtime version="8.0+"/>
    </resources>
    <resources>
    <j2se version="1.8+" href="http://java.sun.com/products/autodl/j2se"/>
    <jar href="HelloWorldPreloader.jar" size="10774" download="progress" />
    <jar href="HelloWorldFX.jar" size="248884114" download="eager" main="true" />
    </resources>
    <jfx:javafx-desc width="600" height="400" main-class="sample.Main" name="HelloWorldFX" preloader-class="HelloWorldPreloader"/>
    <update check="always"/>
    </jnlp>

    关于java - 如何在预加载器中处理 java web start (jnlp) 下载进度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35849930/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com