framework - Cómo detener "Hilo de aplicación JavaFX"
javafx netbeans (4)
Tengo una aplicación de consola simple que a veces necesita realizar operaciones gráficas, para las que estoy usando JavaFx framework (hay algunas funciones que necesito como el estilo css para texto) Simplemente genero algunas formas y texto en una escena oculta y luego guardo los archivados y eso es todo,
Sé que para trabajar con JavaFx tengo que pasar operaciones de gráficos al subproceso de JavaFx, pero cuando todo está listo y tengo que cerrar la aplicación (después de algunas horas), este subproceso de JavaFx aún permanece abierto ... y realmente no lo hago. deseo forzar la salida con System.exit () porque si algo está bloqueado, es posible que desee saber / esperar (TAMBIÉN no quiero ejecutar todo como una aplicación JavaFx (ya que los componentes JavaFx son menos del 1% de mi aplicación principal)
El código es muy simple y busco en Google que he encontrado solo para usar
Platform.exit();
que no parece funcionar, también he intentado jugar con parámetros de plataforma como
Platform.setImplicitExit(false);
Aquí está mi aplicación de prueba que puedes ejecutar:
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.geometry.Pos;
import javafx.scene.layout.VBox;
public class SOTestFX {
public static void main(String[] args) {
SOTestFX t = new SOTestFX();
t.runFxThread();
}
public void runFxThread(){
//Application.launch(args);
final JFXPanel jfxPanel = new JFXPanel();
Platform.runLater(new Runnable() {
@Override
public void run() {
System.err.println("CREATING IMAGE");
simpleFXoperations();
System.err.println("NOW CALL EXIT");
System.err.println("JAVA FX THREAD SHOULD BE EXITED NOW");
Platform.exit();
}
});
try {
Thread.sleep(3000); // just wait a bit if something should happen, let it happen..
} catch (InterruptedException e) {
e.printStackTrace();
}
//jfxPanel.removeNotify(); // return -> java.lang.NullPointerException
//Platform.exit(); // -> does nothing
System.err.println("i will never die!");
}
public void simpleFXoperations(){
VBox vbox1 = new VBox();
vbox1.setAlignment(Pos.BOTTOM_CENTER);
vbox1.setStyle("-fx-border-style: solid;"
+ "-fx-border-width: 1;"
+ "-fx-border-color: white");
System.err.println("simpleFXoperations() _DONE");
}
}
Y este es el hilo que nunca se cierra.
"Attach Listener" - Thread t @ 17 java.lang.Thread.State: RUNNABLE
Sincronizadores propios bloqueados: - Ninguno
"JavaFX Application Thread" - Thread t @ 13 java.lang.Thread.State: RUNNABLE en com.sun.glass.ui.gtk.GtkApplication._runLoop (Método nativo) en com.sun.glass.ui.gtk.GtkApplication $ 3 $ 1.run (GtkApplication.java:82) en java.lang.Thread.run (Thread.java:722)
Sincronizadores propios bloqueados: - Ninguno
Actualización: Estoy usando la última versión de Oracle JDK 7u17 64bit en Linux Fedora 16 64bit.
Fijar:
Pude solucionar este problema llamando a com.sun.javafx.application.PlatformImpl.tkExit()
inmediatamente antes de Platform.exit()
. Realmente no entiendo muy bien la fuente de JavaFX, pero parece estar funcionando; YMMV.
Actualización: Al hacer esto en Java 8 se producirá una advertencia, simplemente puede desactivar la advertencia con @SuppressWarnings("restriction")
. No debería ser un problema.
Explicación:
Descubrí esto buscando en el código fuente; JFXPanel
tiene este pequeño fragmento (esto es de JavaFX 2.2.25)
finishListener = new PlatformImpl.FinishListener() {
public void idle(boolean paramAnonymousBoolean) {
if (!JFXPanel.firstPanelShown) {
return;
}
PlatformImpl.removeListener(JFXPanel.finishListener);
JFXPanel.access$102(null);
if (paramAnonymousBoolean)
Platform.exit();
}
public void exitCalled()
{
}
El problema es que si está usando solo un poco de JavaFX en su aplicación, entonces el método idle(boolean)
nunca hace nada (porque firstPanelShown == false
), lo que impide que se elimine el oyente, lo que impide que el Toolkit
de Toolkit
JavaFX apagando ... lo que significa que tienes que apagarlo manualmente.
Esa es una situación resbaladiza, ya que (a mi entender) el propósito del subproceso de JavaFX es sacar provecho de varias tuberías de hardware de manera transparente. ¿Puedo sugerirle que coloque sus solicitudes de JavaFX en un proyecto separado y referenciado? ¿Y guardar todo lo demás, incluido tu método principal, en otro? Eso siempre me ha funcionado.
Básicamente, la lógica de negocios y el modelo van en un proyecto, y la vista y el control (generalmente basados en JavaFX) van en el otro. Esto permite la terminación independiente del subproceso JavaFX. Esperemos que sea aplicable a lo que está tratando de hacer.
Intenté muchas cosas con esto ya que ninguna de las respuestas anteriores funcionó para mí. Lo mejor para mí fue apagar toda la JVM utilizando
System.exit(1);
ya que mi aplicación completa es solo una aplicación JavaFX y, por lo tanto, puede cerrarse al cerrar el escenario. El 1 en mi caso es solo un int aleatorio.
Su función principal no pertenece al objeto de la aplicación JavaFx y creo que su programa nunca entra en el bucle de subprocesos de la aplicación.
Parece que deberías hacer:
public class SOTestFX extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
// Do stuff here to show your stage or whatever you want;
// This will be called on the JavaFX thread
}
}