Java 摇摆音播放提前结束

Java swing sound playback ends prematurely

在 Java swing 应用程序中,以下代码片段用于播放警报器。它开始正常但过早停止,并不总是同时停止(即有时它几乎立即停止,有时在更长的延迟后停止,但通常它不会完成播放整个声音文件)。可能是什么原因造成的?

我已尽力创建一个仍然存在问题的最小示例:

package monster;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.io.File;
import javafx.embed.swing.JFXPanel;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Example_2 extends JPanel {

    protected static final long serialVersionUID = 1L;

    public Example_2() {
        setPreferredSize(new Dimension(100,100));
        setBackground(Color.white);
        createPanel();
    }

    public static void main(String[] args) {
        Example_2 e = new Example_2();
        JFrame f    = new JFrame();
        f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        f.add(e, BorderLayout.CENTER);
        f.pack();
        f.setVisible(true);
        f.repaint();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        new Thread(
            new Runnable() {
                public void run() {
                    try {
                        File f = new File("sound/siren_short.wav");
                        String url = "file:///"+f.getAbsolutePath().replaceAll("\\","/").replaceAll(" ", "%20");
                        MediaPlayer mp = new MediaPlayer(new Media(url));
                        mp.play();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    }

    public static JFXPanel createPanel() {
        return new JFXPanel();
    }

}

在 "Example2" 发布的当前示例代码中,在我看来 main() 执行并退出。是的,对 MediaPlayer 的调用会启动一个后台线程,但我猜 main() 结束时,这也会终止 MediaPlayer 线程(可能是因为它只有守护进程状态)。我自己还没有使用过 MediaPlayer,所以我不知道是否会导致这种行为。

这里有一个简单的测试:添加以下行。

Thread.sleep(5000); // pauses 5 seconds

或类似于 main() 结尾的内容,在 repaint() 调用之后。这个数字是毫秒:使用一个比你的声音长度长的数字。现在声音播放完毕了吗?您可能必须将新代码行放在 try...catch 块中。

有机会时查看 Thread() 的 api。当您到达该页面时,我建议您在 "daemon" 上进行搜索。有测试或设置守护程序状态的方法,以及状态含义的简要说明。如果您将 运行nable 设置为 not 有可能成为守护程序,程序(如图所示)将播放一次然后挂起,无法终止它,除非通过 Eclipse(如果它在 Eclipse 中是 运行)或通过 OS 任务管理器杀死它。

我没有深入研究 Eclipse 中的调试线程——恐怕我不能在那里提供任何建议。

Andrew Thompson 提出了一个很好的建议,利用 Clip。这有利于让我们保持在 "familiar" 范围内。我经常使用 Clip,但没有使用 JavaFX 库。如果你 had 使用 Clip,我建议的代码行 (Thread.sleep) 肯定需要允许声音播放完成。

这是一个理论:加载和执行play()命令的代码是非守护程序。但是,将声音数据传送到线路的后台进程是守护进程。如果真是这样,那么我描述的行为(在主线程完成后终止)将是一致的。