首页 > 解决方案 > 为什么这个 JavaFX 播放器会死机?

问题描述

我正在尝试使用以下播放器:

public class JavaFXPlayer extends Application {
  private MediaPlayer mediaPlayer;
  private Media media;

  public JavaFXPlayer(String strUrl) {
    this.media = new Media(strUrl);
  }
  public void play() {
    Application.launch();
  }
  @Override
  public void start(Stage primaryStage) throws Exception {
    mediaPlayer = new MediaPlayer(media);

    // by setting this property to true, the audio will be played
    mediaPlayer.setAutoPlay(true);
    primaryStage.setTitle("Playing Audio");
    primaryStage.show();
  }

  @Override
  public void stop() {
    if (mediaPlayer != null) {
      mediaPlayer.stop();
      mediaPlayer.dispose();
    }
  }
}

然后我像这样运行:

JavaFXPlayer player = new JavaFXPlayer(strUrl);
player.play();

但是,当我运行时,我的整个程序会立即冻结player.play()。这是为什么?

标签: javafx

解决方案


通过运行时启动 JavaFX 应用程序时,会通过反射为您Application#launch创建子类的实例。Application这给实现带来了一些限制:

  • 它必须是一个public类。
  • 它必须有一个public无参数的构造函数。
  • 如果使用模块,那么它的包必须至少导出到javafx.graphics模块。

如果您使用您的Application子类作为应用程序的主类,那么您不需要 main 方法——至少对于 JavaFX 版本 8-12 1不需要。如果你确实有一个 main 方法,它应该看起来像这样:

public class MyApp extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception { ... }

}

您还可以将其他一些类函数作为主类:

public class Main {

    public static void main(String[] args) {
        Application.launch(MyApp.class, args);
    }

}

无论您选择使用哪个,您都必须有一个公共的、无参数的构造函数。这意味着您失去了Media通过构造函数传入 URL 的能力。也不清楚这个 URL 来自哪里。如果 URL 来自命令行参数,那么Applicationstart(Stage)可以init()通过Application#getParameters(). 如果 URL 是硬编码的,您只需要以不同的方式使用它(例如,直接在Application子类中)。

尽管如此,我不完全确定您的应用程序为什么会冻结,因为您没有提供最小的可重现示例。但是,线程调用Application#launch在该方法调用中被阻塞,直到 JavaFX 运行时退出。这意味着如果您在所述线程上调用该方法,您可能会阻塞JavaFX 应用程序线程。


1. JavaFX 有特殊处理,只要主类是Application. 但是,随着版本 11 从 JDK 中删除 JavaFX,此功能可能会在将来的版本中删除。


推荐阅读