JavaFX 2.1 和线程? - 或 - 优雅地结束 JavaFX 应用程序?

标签 java multithreading javafx-2 exit

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

因此,在我第一次使用 JavaFX 进行实验时,我使用了 stackoverflow ( see here ) 的帖子中建议的一些代码,并基本上创建了以下测试程序:

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 为回应我之前发布的关于让程序完全运行的问题 (see here) 提出的建议而产生的。)

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

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

}

下面是 Msg 线程的代码,它应该实际播放 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() */

}

(我使用与上述相同的命令构建并运行了这些文件(对文件名和类名进行了必要的必要修改)。)

程序运行并播放 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() 调用。现在播放了音频,但是节目并没有再次结束。

呃!

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

提前致谢!

最佳答案

在第一个 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)

Sets the implicitExit attribute to the specified value. If this attribute is true, the JavaFX runtime will implicitly shutdown when the last window is closed; the JavaFX launcher will call the Application.stop() method and terminate the JavaFX application thread. If this attribute is false, the application will continue to run normally even after the last window is closed, until the application calls exit(). The default value is true.

这应该会为您提供有关您遇到的问题的一些线索。

关于JavaFX 2.1 和线程? - 或 - 优雅地结束 JavaFX 应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10902799/

相关文章:

java - 应用程序关闭后 MediaPlayer 继续播放

java - 线程在进入下一个 Activity 之前保持更新一段时间,并且冲突已关闭

c - 如果在 linux 中花费的时间超过阈值时间,如何终止子线程

HTML 中的 JavaFX 组件?

java - 焦点 JavaFX FXML 上的 KeyEvent

java - EntityManager 真的是线程安全的吗?

java - 使用 Micronaut Serialization 进行泛型反序列化,而不使用 @SuppressWarnings ("unchecked")

java - JMH基准测试中的参数列表

JAVA消费者-生产者多线程应用程序——代码流程

javafx - 使用 javafx 显示消息框