2012-06-05 10 views
5

Quería una manera muy simple de reproducir un archivo mp3 desde una aplicación Java. Después de algunas investigaciones, descubrí que las versiones más recientes de Java 7 SE están empacadas con JavaFX, así que pensé que lo intentaría. Esta pregunta NO se trata de reproducir archivos mp3, sino de hacer que JavaFX funcione de forma correcta.JavaFX 2.1 y subprocesos? -o bien - ¿Finaliza una aplicación JavaFX correctamente?

Por lo tanto, en mi primer experimento con JavaFX, he utilizado un código sugerido en un puesto de stackoverflow (see here) y creó, en esencia, el siguiente programa de prueba:

import javafx.application.Application; 
import javafx.stage.Stage; 
import javafx.scene.media.Media; 
import javafx.scene.media.MediaPlayer; 

public class progtest extends Application 
{ 

    /*---------------------------------------------------------*\ 
     FUNCTION: main() 
    \*---------------------------------------------------------*/ 
    public static void main(String args[]) 
    { 

     launch(args); 

    } /* END: main() */ 

    /*---------------------------------------------------------*\ 
     FUNCTION: start() 
    \*---------------------------------------------------------*/ 
    @Override 
    public void start(Stage stage) 
    { 

     Media medMsg 
      = 
      new Media(getClass().getResource("msg.mp3").toExternalForm()); 
     MediaPlayer medplMsg = new MediaPlayer(medMsg); 
     medplMsg.play(); 

     System.out.println("Here.\n"); 

    } /* END: start() */ 

} 

(Esto es un poco más sofisticado que mi programa de prueba original: esta versión se produjo después de las sugerencias de jewelsea hechas en respuesta a una pregunta anterior que he publicado acerca de cómo obtener el programa que se ejecuta en absoluto (see here))

para compilar el código utilicé:.

javac -cp "c:\Program Files\Oracle\JavaFX 2.1 Runtime\lib\jfxrt.jar";..\bin -d ..\bin ..\src\progtest.java 

Y, para ejecutar el código Fui a mi .. \ bin y utilicé:

java -cp .;"c:\Program Files\Oracle\JavaFX 2.1 Runtime\lib\jfxrt.jar" progtest 

Este programa corre y juega la reproducción del clip. Sin embargo, el programa no regresa al símbolo del sistema a menos que haga una Ctrl-C.

Ese comportamiento parecía un tipo de problema de hilo. He visto este tipo de comportamiento muchas veces trabajando con subprocesos de Java (que, lamentablemente, tienen problemas reales que permiten salidas graciosas de los programas).

Entonces, pensé, quizás si pongo el código en su propio hilo y luego termino el hilo principal del programa cuando termina ese hilo, las cosas estarían bien. (Pude ver que esto no era del todo un pensamiento coherente, pero de todos modos, pensé que iba a tratar.) Por lo tanto, escribí la siguiente segunda versión del código:

Aquí está el hilo principal:

import javafx.application.Application; 
import javafx.stage.Stage; 
import Msg.*; 

public class progtest2 extends Application 
{ 

    /*---------------------------------------------------------*\ 
     FUNCTION: main() 
    \*---------------------------------------------------------*/ 
    public static void main(String args[]) 
    { 

     launch(args); 

    } /* END: main() */ 

    /*---------------------------------------------------------*\ 
     FUNCTION: start() 
    \*---------------------------------------------------------*/ 
    @Override 
    public void start(Stage stage) 
    { 

     Msg msgTime = new Msg(); 
     msgTime.passClass(getClass()); 
     msgTime.start(); 

     try 
     { 
      msgTime.join(); 
     } 
     catch (InterruptedException e) 
     { 
     } 

     System.out.println("Here.\n"); 

    } /* END: start() */ 

} 

y aquí está el código para el hilo de mensajes que en realidad debería reproducir el archivo MP3:

package Msg; 

import KeyIO.*; 
import javafx.application.Application; 
import javafx.scene.media.Media; 
import javafx.scene.media.MediaPlayer; 

public class Msg extends Thread 
{ 

    private Class classRt = null; 

    /*--------------------------------------------------------*\ 
     FUNCTION: passClass() 
    \*--------------------------------------------------------*/ 
    public void passClass(Class rt) 
    { 

     classRt = rt; 

    } /* END: passClass() */ 

    /*--------------------------------------------------------*\ 
     FUNCTION: run() 
    \*--------------------------------------------------------*/ 
    public void run() 
    { 

     Media medMsg 
      = new Media(classRt.getResource("msg.mp3").toExternalForm()); 
     MediaPlayer medplMsg = new MediaPlayer(medMsg); 
     medplMsg.play(); 

     System.out.println("Leaving Msg thread.\n"); 

    } /* END: run() */ 

} 

(I construyó y gestionó estos archivos con el mismo comando (mutatis mutandis re los nombres de archivo y los nombres de las clases) que el anterior.)

El programa ejecuta y reproduce el archivo mp3. Antes de escuchar el archivo, verá "Dejar hilo Msg". y luego "Aquí.", que como puede ver provienen del hilo Msg y el hilo principal, respectivamente. Pero, nuevamente, el programa no termina. Tengo que presionar Ctrl-C para regresar al símbolo del sistema.

Puse una llamada System.exit() justo al final del hilo principal allí solo para ver cuál sería el comportamiento. El comportamiento fue que el clip no se escuchó. Parecía que la llamada System.exit() finalizaba el proceso antes de reproducir el clip.

Por lo tanto, a continuación intenté poner las siguientes líneas entre System.out.println ("Here. \ N"); y la System.exit() llamada que hice:.

System.out.print("Press ENTER to end..."); 
KeyIO.ReadLine(); 

(KeyIO es una clase que hice sólo por hacer la salida la entrada del teclado simplemente Los detalles no son realmente relevante aquí.)

Pensé que esto simplemente bloquearía el hilo principal para avanzar hasta que se reprodujera el clip.

Pero, no. En cambio, el clip no se reprodujo. Cuando presiono ENTER, el programa salió sin reproducir el clip.

Bien, entonces dejé ese código de bloqueo de entrada de teclado, pero saqué la llamada a System.exit(). Ahora se reproducía el clip de audio, pero el programa no terminaba de nuevo.

Urgh!

¿Alguna idea de cómo hacer que esto funcione correctamente de la manera en que es obvio que uno quisiera que funcione? Solo quiero hacer una llamada para reproducir el clip, y luego quiero poder finalizar el programa.

¡Gracias de antemano!

Respuesta

8

En la primera clase de progtest, no crea una ventana, por lo que la acción implicitExit al cerrar la última ventana no se invoca. Esto significa que el programa seguirá ejecutándose hasta que llame al método de salida de la aplicación, lo cual no hace.

Para que el programa salga después de que su mp3 haya terminado de reproducirse, llame al mediaPlayer.setOnEndOfMedia(runnable) y en la devolución de llamada ejecutable invoque el método Platform.exit().

medplMsg.setOnEndOfMedia(new Runnable() { 
    @Override public void run() { 
    Platform.exit(); 
    } 
}); 

No se requieren todas las otras cosas para enhebrar en su pregunta (y de todos modos no resuelve su problema ...). No recomendaría el uso de subprocesos personalizados a menos que realmente lo necesite (que no lo necesita).

JavaFX 2.2 añade la siguiente API:

Platform.setImplicitExit(boolean implicitExit) 

establece el atributo implicitExit al valor especificado. Si este atributo es verdadero, el tiempo de ejecución de JavaFX se apagará implícitamente cuando se cierre la última ventana; el iniciador JavaFX llamará al método Application.stop() y terminará el subproceso de la aplicación JavaFX. Si este atributo es falso, la aplicación continuará ejecutándose normalmente incluso después de que se cierre la última ventana, hasta que la aplicación llame a exit(). El valor por defecto es verdadero.

Esto debería darle alguna pista sobre los problemas que está teniendo.

+0

¡Excelente! Funciona a las mil maravillas. Publicaré el código completo a continuación. ¡Gracias, jewelsea! Muy útil. Y me ha dado mucha información acerca de cómo puedo descubrir algunas de estas cosas en el futuro. Gracias. –

0

Esta respuesta a mi propia pregunta es dar un ejemplo definitivo del código que finalmente resolvió el problema que proviene de las excelentes respuestas de jewelsea en este hilo y el otro al que me refiero en mi publicación original.

bien, así que el siguiente código trabajó (y jewelsea tenía razón al comentar que el roscado es innecesario y junto a cualquier punto aquí):

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.stage.Stage; 
import javafx.scene.media.Media; 
import javafx.scene.media.MediaPlayer; 

public class progtest6 extends Application 
{ 

    /*---------------------------------------------------------*\ 
     FUNCTION: main() 
    \*---------------------------------------------------------*/ 
    public static void main(String args[]) 
    { 

     launch(args); 

    } /* END: main() */ 

    /*---------------------------------------------------------*\ 
     FUNCTION: start() 
    \*---------------------------------------------------------*/ 
    @Override 
    public void start(Stage stage) 
    { 

     Media medMsg 
      = 
      new Media(getClass().getResource("msg.mp3").toExternalForm()); 
     MediaPlayer medplMsg = new MediaPlayer(medMsg); 
     medplMsg.setOnEndOfMedia(new Runnable() { 
      @Override 
      public void run() 
      { 
       Platform.exit(); 
      } 
     }); 
     medplMsg.play(); 

     System.out.println("Here.\n"); 

    } /* END: start() */ 

} 

Gracias jewelsea.