5

我想要一种非常简单的方法来从 Java 应用程序播放 mp3 文件。经过一番研究,我发现最新版本的 Java 7 SE 是用 JavaFX 打包的,所以我想我会尝试一下。这个问题不是关于播放 mp3 文件,而是关于让 JavaFX 以一种行为良好的方式工作。

因此,在我对 JavaFX 的第一次实验中,我使用了一些在 stackoverflow 帖子中建议的代码(请参见此处),并创建了以下测试程序:

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() */

}

(这比我原来的测试程序稍微复杂一点:这个版本是在jewelsea 提出的建议之后出现的,该建议是为了回应我之前发布的关于让程序运行的问题(见这里)。)

为了编译我使用的这段代码:

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

而且,为了运行代码,我进入了我的 ..\bin 目录并使用了:

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

该程序运行并播放剪辑播放。但是,除非我按 Ctrl-C,否则程序不会返回到命令提示符。

这种行为似乎是某种线程问题。我已经多次看到这种行为与 Java 线程一起使用(遗憾的是,在允许程序优雅退出时存在真正的问题)。

所以,我想,也许如果我将代码放在它自己的线程中,然后在该线程结束时结束程序的主线程,一切都会好起来的。(我可以看出这并不完全是一个有说服力的想法,但无论如何,我想我会尝试。)所以,我编写了以下第二个版本的代码:

这是主线程:

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() */

}

下面是实际播放 mp3 文件的 Msg 线程的代码:

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() */

}

(我使用与上述相同的命令(比照文件名和类名)构建并运行这些文件。)

该程序运行并播放 mp3 文件。在您听到文件之前,您会看到“Leaving Msg thread”。然后是“Here.”,如您所见,它分别来自 Msg 线程和主线程。但是,同样,程序并没有结束。我必须按 Ctrl-C 才能返回命令提示符。

我在主线程的末尾放了一个 System.exit() 调用,只是为了看看行为会是什么。行为是没有听到剪辑。似乎 System.exit() 调用在播放剪辑之前结束了该过程。

因此,接下来我尝试将以下几行放在 System.out.println("Here.\n"); 之间 和我所做的 System.exit() 调用:

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

(KeyIO 是我做的一个类,只是为了简单地做键盘输入输出。细节在这里并不相关。)

我认为这只会阻止主线程继续前进,直到播放剪辑。

但不是。相反,该剪辑没有播放。当我按 ENTER 时,程序退出而不播放剪辑。

好的,所以现在我留下了键盘输入阻塞代码,但我取出了 System.exit() 调用。现在播放了音频剪辑,但程序没有再次结束。

啊!

有什么想法可以优雅地让它以一种显而易见的方式工作吗?我只想打电话播放剪辑,然后我希望能够结束程序。

先感谢您!

4

2 回答 2

7

在第一个 progtest 类中,您不创建窗口,因此不会调用关闭最后一个窗口时的implicitExit 操作。这意味着程序将继续运行,直到您调用应用程序的退出方法,而您不这样做。

要让程序在您的 mp3 播放完毕后退出,请调用mediaPlayer.setOnEndOfMedia(runnable)并在可运行回调中调用Platform.exit()方法。

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

不需要您问题中的所有其他线程内容(无论如何也不能解决您的问题......)。我不建议使用自定义线程,除非你真的需要它(你不需要)。

JavaFX 2.2 添加了以下 api:

Platform.setImplicitExit(boolean implicitExit)

将implicitExit 属性设置为指定值。如果此属性为真,JavaFX 运行时将在最后一个窗口关闭时隐式关闭;JavaFX 启动器将调用 Application.stop() 方法并终止 JavaFX 应用程序线程。如果此属性为 false,则即使在最后一个窗口关闭后,应用程序仍将继续正常运行,直到应用程序调用 exit()。默认值是true。

这应该会给你一些关于你遇到的问题的线索。

于 2012-06-05T21:51:30.707 回答
0

这个对我自己的问题的回答是给出一个最终解决问题的代码的明确示例,该问题来自jewelsea 在该线程中的出色响应以及我在原始帖子中提到的另一个问题。

好的,所以下面的代码起作用了(jewelsea 正确地评论说线程是不必要的并且在这里没有任何意义):

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() */

}

谢谢珠宝海。

于 2012-06-05T22:52:13.057 回答