多个媒体文件需要多个 MediaPlayer 吗?

Do I need multiple MediaPlayers for multiple media files?

我正在使用 JavaFX 开发一个音乐库应用程序,我在正确使用 MediaPlayer 的方式上遇到了一些问题 class。

这是我目前设置和播放音频文件的方法:

private static MediaPlayer musicPlayer;

public static void setMedia(String path) {
    try {
        musicPlayer = new MediaPlayer(new Media(new File(path).toURI().toASCIIString()));
        musicPlayer.play();
    } catch (Exception e) {
        System.out.println("invald file");
        System.out.println(e.getMessage());
    }
}

比如说,我有两个音频文件...

file1.mp3
file2.mp3

...以及将这两个文件之一发送到上述方法的两个按钮:

button1.setOnAction(event -> {
    setMedia("file1.mp3");
});

button2.setOnAction(event -> {
    setMedia("file2.mp3");
});

通常情况下,两个音频文件会相互播放是有意义的,因为我每次调用该方法时都会创建一个新的 MediaPlayer 对象,但是,该对象是静态的。也许我误解了静态对象的工作方式,但这不应该意味着这个对象只能有一个实例吗?反过来,这是否意味着无论何时调用 setMedia 方法,MediaPlayer 对象的媒体都会被覆盖?

我还没有找到任何方法来 "set" 或 "overwrite" MediaPlayer 对象的媒体而不创建它的新实例。它似乎没有这样做的方法。 这让我相信我必须为每个音频文件创建一个 MediaPlayer 对象数组。这个对吗?或者我只是在这里遗漏了什么?

您似乎混淆了两个概念:静态变量与单例。你在这里说的 there can only ever be one instance of this object 适用于单例,但不适用于一般的静态变量。对于静态变量,仅表示该变量的作用域是全局的。换句话说,这个变量只有一个引用。

一个例子:

// This is just a general static variable
private static MediaPlayer mediaPlayer;
mediaPlayer = new MediaPlayer(...);
mediaPlayer = new MediaPlayer(...); // this second assignment is ok

// This is a singleton - note the key word `final`
private static final MediaPlayer mediaPlayer;
mediaPlayer = new MediaPlayer(...); // ok
mediaPlayer = new MediaPlayer(...); // compile error

I have not found any way to "set" or "overwrite" media for a MediaPlayer object without creating a new instance of it. It does not appear to have a method to do so. This leads me to believe that I must have an array of MediaPlayer objects for each audio file. Is this correct? Or am I simply missing something here?

没错。 documentation for the MediaPlayer constructor 明确说明了这一点:

public MediaPlayer(Media media)

Create a player for a specific media. This is the only way to associate a Media object with a MediaPlayer: once the player is created it cannot be changed.


Maybe I am misinterpreting how static objects work, but shouldn't it mean that there can only ever be one instance of this object?

是的,你误解了这一点。

引用 MediaPlayer 静态仅仅意味着你的 class 只有一个引用 MediaPlayer。 (通常的说法是,单个 MediaPlayer 引用是你的 class 的“所有实例共享”。我不喜欢这样:它有点暗示你必须至少有一个实例您的 class,这不是真的。将其设为静态实际上仅意味着 MediaPlayer 引用是 class 的 属性,而不是 属性 的 属性 class.) 的简单替换引用(使其引用不同的 MediaPlayer)不会从堆中删除先前的对象。它仍然存在于内存中,仍然具有它的所有属性,等等。你的 class 只是不再有对它的引用。

一般来说,如果没有对对象的实时引用,那么它就有资格进行垃圾回收。然而,在这种情况下,如果媒体正在播放,则 FX 工具包将维护对它的引用,以使其保持实际物理播放。 MediaPlayer定义了一个dispose方法来释放其底层资源。所以你的方法应该看起来像这样:

public static void setMedia(String path) {

    if (mediaPlayer != null) {
        mediaPlayer.stop();
        mediaPlayer.dispose();
    }
    try {
        musicPlayer = new MediaPlayer(new Media(new File(path).toURI().toASCIIString()));
        musicPlayer.play();
    } catch (Exception e) {
        System.out.println("invald file");
        System.out.println(e.getMessage());
    }
}

几乎可以肯定没有必要制作所有东西static:它对你没有任何帮助。