start ejemplo descargar chrome assessment archivos abrir java javafx-8 java-web-start jnlp

java - ejemplo - jnlp windows 10



¿Cómo manejar el progreso de la descarga de java web start(jnlp) en un preloader? (2)

Problema

Tengo un precargador para mi aplicación que maneja la inicialización específica de la aplicación. Ahora estoy intentando extender esto para que el precargador también muestre el progreso de los archivos JAR descargados.

TL; DR

  • ¿Por qué no se carga el preloader durante la Fase 2 , ya que esto debería manejar el PreloaderFx::handleProgressNotification(); para rastrear la descarga de los archivos JAR supongo?

  • Actualización 14 de marzo de 2016 : ¿Está utilizando DownloadServiceListener la forma de resolver esto? ¿Cómo conectar esto a un escenario JavaFX?

Documentación

Según Oracle , hay 4 fases cuando se lanza una aplicación:

  • Fase 1: Inicialización : la inicialización de Java Runtime y un examen inicial identifica los componentes que se deben cargar y ejecutar antes de iniciar la aplicación. Durante esta fase, se muestra una pantalla de bienvenida. Por defecto esto es esto:

  • Fase 2: carga y preparación : los recursos necesarios se cargan desde la red o desde una memoria caché de disco, y se producen los procedimientos de validación. Todos los modos de ejecución ven el valor predeterminado o un preloader personalizado. Durante esta fase, se debe mostrar mi preloader personalizado.

  • Fase 3: Inicialización específica de la aplicación: la aplicación se inicia, pero es posible que deba cargar recursos adicionales o realizar otras preparaciones prolongadas antes de que sea completamente funcional. En este momento, se muestra mi preloader personalizado:

  • Fase 4: Ejecución de la aplicación : la aplicación se muestra y está lista para usar. En mi caso, se muestra una ventana de inicio de sesión y el usuario puede continuar.

Mi caso

Lo primero que noté, es que en la Fase 2 , el precargador JavaFX predeterminado que maneja la descarga de los archivos JAR de la aplicación no se muestra. Debido a esto, el usuario tiene la sensación de que el programa no se inició o finalizó prematuramente, lo que hace que abra el archivo JNLP varias veces. Una vez que se descargan los JARs, ingresamos a la Fase 3 y se muestra el precargador.

Sin embargo, me gustaría que mi preloader personalizado también maneje el progreso de la descarga en la Barra de progreso (Fase 2). Hice todo lo más simple posible para rastrear qué eventos están sucediendo durante el inicio de mi aplicación. Esto se basa en un ejemplo de Jewelsea y en ejemplos de Oracle :

Precargador

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

El código que se está manejando en la Fase 3 es de la aplicación principal que interactúa con el precargador, esto es lo que se ve en la barra de progreso:

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>

Depuración

Observé de cerca la consola de Java al iniciar el archivo (con Mostrar registro habilitado, Mostrar rastreo deshabilitado) y noté lo siguiente:

Durante la Fase 2 , no aparece nada en la Consola Java (la consola se cierra después de esta fase)

Durante la Fase 3 , se genera la siguiente salida (en una nueva ventana de consola):

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

Actualizaciones 13 de marzo de 2016:

  • Ajustó el código para que se use la etapa pasada en el método en lugar de crear uno nuevo y comenta todo lo relacionado con el booleano noLoadingProgress (sugerido por nhylated)
  • Se agregó un poco de System.out.println() adicional en MainApp

Solución

La simple adición de <jfx:javafx-runtime version="8.0+"/> al archivo JNLP lo solucionó. Con esa línea agregada, el precargador se muestra en la Fase 2. También me tomé la libertad de cambiar la j2se version="1.6+" a la j2se version="1.8+" El resultado:

El primer 50% es el manejo de las descargas de JAR. Esto se hace mediante el método handleProgressNotification() . El segundo 50% es la inicialización real de MainApp ( longstart() que notifica al preloader), realizada por el handleApplicationNotification() .


He estado peleando con esto también, recientemente. Cambié de nuevo al precargador predeterminado (feo) (ya que este se ve bien) hasta que encuentre más tiempo para investigar esto.

Si habilita el seguimiento completo de Java Webstart

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

debería ver los mensajes de precargador que deberían proporcionarle información sobre lo que está sucediendo. En mi caso pude ver muchos mensajes como estos.

preloader: Added pending event 2: DownloadEvent[type=load,loaded=0, total=62791, percent=0]

indica que el preloader personalizado aún no se ha verificado / iniciado, pero los eventos de descarga ya estaban llegando.

¿Qué sucede si cambia <update check="background"/> a <update check="always"/> ?

EDITAR

Esta es mi prueba JNLP. Parece que te falta especificar el recurso de tiempo de ejecución de 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>


Nota: No he probado ni ejecutado el código; Mi respuesta se basa principalmente en mirar el código. No he trabajado en JavaFX pero puedo entender el código ya que he trabajado en Swing y JNLP anteriormente.

Lo primero que noté, es que en la Fase 2, el precargador JavaFX predeterminado que maneja la descarga de los archivos JAR de la aplicación no se muestra.

Esto parece ser debido al método PreloaderFX.start(stage) . La stage pasada como el argumento del método permanece vacía porque el método construye una new Stage() y le agrega elementos secundarios. Si agrega los elementos secundarios al argumento del método, debería mostrar su preloader / barra de progreso personalizado durante la fase 2.

Si el código sigue sin funcionar como se esperaba después de esto, intentaría depurar toda la lógica / código asociado con el indicador noLoadingProgress . Trate de comentar todo eso (esencialmente noLoadingProgress a noLoadingProgress de la imagen) y vea si soluciona el problema.

Además, aunque tenga este derecho en su código, vea this respuesta, según la cual todas las handleApplicationNotification ProgressNotification son manejadas por el método handleApplicationNotification .

¡Espero que esto ayude!