【问题标题】:Java FX Null Pointer Exception when using Media Player at javafx.scene.media.MediaPlayer.init在 javafx.scene.media.MediaPlayer.init 中使用媒体播放器时出现 Java FX 空指针异常
【发布时间】:2015-04-26 23:53:50
【问题描述】:

启动 MediaPlayer 的媒体块中没有空字段

我对此进行了广泛的研究,但没有发现任何可以解释此错误的原因。

我正在为一个类项目构建一个 Java Swing 应用程序,并尝试使用 JFX 面板和媒体播放器来托管和播放多个 mp4 视频。我已经成功让它工作了一次,但是当我再次回到窗口时,我遇到了错误。

java.lang.NullPointerException 在 com.sun.media.jfxmediaimpl.platform.gstreamer.GSTMediaPlayer.playerSetBalance(未知 来源)在 com.sun.media.jfxmediaimpl.NativeMediaPlayer.setBalance(未知 源)在 javafx.scene.media.MediaPlayer.init(未知源)在 javafx.scene.media.MediaPlayer.(Unknown Source) at project.screens.TutorialPlayerScreen.initMediaPlayer(TutorialPlayerScreen.java:156) 在 project.screens.TutorialPlayerScreen.init(TutorialPlayerScreen.java:122) 在 project.screens.TutorialPlayerScreen.(TutorialPlayerScreen.java:113) 在 project.buttons.PreKModuleSelectTutorialButtons$Button$7.doAction(PreKModuleSelectTutorialButtons.java:225) 在 project.screens.PreKModuleSelect.clicked(PreKModuleSelect.java:359) 在 project.tools.ContentPane.notifiyObserver(ContentPane.java:457) 在 project.tools.ContentPane$1.mousePressed(ContentPane.java:272) 在 java.awt.Component.processMouseEvent(未知来源)在 javax.swing.JComponent.processMouseEvent(未知来源)在 java.awt.Component.processEvent(未知来源)在 java.awt.Container.processEvent(未知来源)在 java.awt.Component.dispatchEventImpl(未知来源)在 java.awt.Container.dispatchEventImpl(未知来源)在 java.awt.Component.dispatchEvent(未知来源)在 java.awt.LightweightDispatcher.retargetMouseEvent(未知来源)在 java.awt.LightweightDispatcher.processMouseEvent(未知来源)在 java.awt.LightweightDispatcher.dispatchEvent(未知来源)在 java.awt.Container.dispatchEventImpl(未知来源)在 java.awt.Window.dispatchEventImpl(未知来源)在 java.awt.Component.dispatchEvent(未知来源)在 java.awt.EventQueue.dispatchEventImpl(未知来源)在 java.awt.EventQueue.access$500(未知来源)在 java.awt.EventQueue$3.run(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) 在 java.security.ProtectionDomain$1.doIntersectionPrivilege(未知 来源)在 java.security.ProtectionDomain$1.doIntersectionPrivilege(未知 源)在 java.awt.EventQueue$4.run(未知源)在 java.awt.EventQueue$4.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) 在 java.security.ProtectionDomain$1.doIntersectionPrivilege(未知 源)在 java.awt.EventQueue.dispatchEvent(未知源)在 java.awt.EventDispatchThread.pumpOneEventForFilters(未知来源) 在 java.awt.EventDispatchThread.pumpEventsForFilter(未知来源) 在 java.awt.EventDispatchThread.pumpEventsForHierarchy(未知 来源)在 java.awt.EventDispatchThread.pumpEvents(未知来源) 在 java.awt.EventDispatchThread.pumpEvents(Unknown Source) 在 java.awt.EventDispatchThread.run(未知来源)

这是我用来启动 JFX 媒体的代码:

' //媒体播放器支持 私人集团媒体根; 私有场景 mediaScene;

private Media tutorialVideo;
private MediaPlayer VideoPlayer;
private MediaView mediaViewer;
private JFXPanel fxPanel;

private int jfxPanelHeight = 394;//525;
private int jfxPanelWidth = 700;//700;

private void initMediaPlayer() throws IOException {
    this.fxPanel = new JFXPanel(); //initializes JFX variables
    fxPanel.setSize(this.jfxPanelWidth ,this.jfxPanelHeight);

    //Add JFX Panel component to the Main Window
    int padding = ((mainWindow.getPreferredSize().width - this.jfxPanelWidth) / 2);
    mainWindow.addLayer(fxPanel, MEDIA_LAYER, padding, 125);

    //Initialize FX Panel
    this.mediaRoot = new Group();
    this.mediaScene = new Scene(this.mediaRoot, 0, 0);

    //Open/prepare the file
    //String tutorialFilePath = new File("").getAbsolutePath() + DIRECTORY_PATH + "Tutorial.mp4";
    String tutorialFilePath = new File("").getAbsolutePath() + MEDIA_PATH + this.observer.getName() +"Tutorial.mp4";
    File mediaFile = new File(tutorialFilePath);
    this.tutorialVideo = new Media(mediaFile.toURI().toString());

    //Create the media player
    this.VideoPlayer = new MediaPlayer(this.tutorialVideo);  //Error here
    this.VideoPlayer.setAutoPlay(false);

    this.mediaViewer = new MediaView(this.VideoPlayer);
    this.mediaViewer.setFitHeight(this.jfxPanelHeight);
    this.mediaViewer.setFitWidth(this.jfxPanelWidth);
          ((Group)this.mediaScene.getRoot()).getChildren().add(this.mediaViewer);

    fxPanel.setScene(this.mediaScene);
}'

我尝试在离开屏幕前清理已使用的内存。

public void tearDown(){

    //Stop the JFX Player and Remove
    this.mainWindow.removeLayer(this.fxPanel);
    this.VideoPlayer.stop();
    this.VideoPlayer.dispose();
    this.fxPanel.removeAll();
    this.mediaRoot.getChildren().removeAll();

    this.mediaRoot = null;
    this.mediaScene = null;
    this.mediaViewer = null;
    this.tutorialVideo  = null;
    this.VideoPlayer = null;
    this.fxPanel = null;
}

private JLayeredPane contentPane;    //The content pane of this JFrame.
public void removeLayer(JComponent component) {
    contentPane.remove(component);
    contentPane.revalidate();
    contentPane.repaint();
}

任何帮助或评论将不胜感激!谢谢!

【问题讨论】:

  • tutorialFilePath 是否真的指向一个有效的文件?
  • @MadProgrammer 是的。第一次运行此代码工作正常。当我进行第二次启动时,我收到一个错误。这一行:this.VideoPlayer = new MediaPlayer(this.tutorialVideo); //这里出错
  • 从到目前为止您向我们展示的内容很难推断,但在您调用 initMediaPlayer 之前,您声明的字段之一肯定是 null
  • 如果它先工作,然后在重新导航后抛出此异常,则在您更改视图时一定发生了一些变化。您的tearDown() 方法似乎很有可能是原因:当您不将这些值设置为null 时会发生什么?你能这样缩小范围吗?您在该方法中删除了很多东西,也许某些东西没有被重建?
  • 这可能不是导致NullPointerException 的问题,但您需要在不同的线程上进行不同的方法调用。特别是,new JFXPanel() 必须在 AWT 事件调度线程上调用,而 initMediaPlayer 的其余部分需要在 FX 应用程序线程上调用。请参阅JFXPanel javadocs。 (虽然这可能不是问题的原因,但可以想象它是。)

标签: java swing javafx


【解决方案1】:

您的代码中存在线程问题,需要修复。具体来说,您必须创建 FX UI 组件并在 FX 应用程序线程上设置场景图。详情请见Javadocs for JFXPanel

不过,这是空指针异常的附带情况。我认为造成这种情况的是,当您从 UI 中完全删除 JFXPanel 时,FX 工具包正在关闭。为了防止这种情况,只需调用

Platform.setImplicitExit(false);

当您第一次初始化您的应用程序时。 (从任何线程调用此方法都是安全的。)

这是一个外观相似的 SSCCE:

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.FlowLayout;

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class MediaPlayerInSwing {

    private static final String MEDIA_URL = "http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv" ;

    private JFrame window ;

    private JFXPanel jfxPanel ;
    private Media media ;
    private MediaPlayer player ;
    private MediaView mediaView ;
    private BorderPane root ;
    private Scene scene ;

    private Button button ;

    // create on AWT Event Dispatch Thread
    public MediaPlayerInSwing() {
        Platform.setImplicitExit(false);
        initGUI();
    }

    private void initGUI()  {
        window = new JFrame();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setLayout(new BorderLayout());

        JPanel controls = new JPanel();
        controls.setLayout(new FlowLayout());
        button = new Button("Show video");
        controls.add(button);
        button.addActionListener(e -> {
            if (jfxPanel == null) {
                showVideo();
            } else {
                tearDownVideo();
            }
        });

        window.add(controls, BorderLayout.SOUTH);
        window.setSize(600, 480);
        window.setLocationRelativeTo(null);
        window.setVisible(true);
    }

    private void showVideo() {


        jfxPanel = new JFXPanel();

        Platform.runLater(() -> {
            media = new Media(MEDIA_URL);
            player = new MediaPlayer(media);
            player.play(); 
            mediaView = new MediaView(player);
            root = new BorderPane(mediaView);
            scene = new Scene(root, 600, 400);
            jfxPanel.setScene(scene);
        });

        window.add(jfxPanel, BorderLayout.CENTER);
        button.setLabel("Hide video");
    }

    private void tearDownVideo() {

        window.remove(jfxPanel);

        Platform.runLater(() -> {
            player.stop();
            player.dispose();
            player = null ;
            mediaView = null ;
            root = null ;
            jfxPanel.setScene(null);
            scene = null ;
            SwingUtilities.invokeLater(() -> {
                jfxPanel = null ;
                // force window to repaint...
                window.getRootPane().repaint();
            });
        });
        button.setLabel("Show video");
    }

    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(MediaPlayerInSwing::new);
    }
}

【讨论】:

    【解决方案2】:

    这可能不是导致 NullPointerException 的问题,但您 需要在不同的线程上进行不同的方法调用。在 特别是,必须在 AWT 事件调度上调用 new JFXPanel() 线程,而 initMediaPlayer 的其余部分需要在 FX 应用程序线程。请参阅 JFXPanel javadocs。 (虽然这 可能不是问题的原因,但可以想象它是。) – 詹姆斯_D

    这解决了问题。

    我将 JFX 面板设置为由主窗口管理,并且永远不会超出范围。为了解决仅在我想要的屏幕上的可见性问题,我将功能更改为这些...

    public void tearDown(){
        this.mediaPanel.getMediaPanel().setVisible(false);
        this.VideoPlayer.stop();
    }
    

    private void initMediaPlayer() throws IOException {
        this.mediaPanel.getMediaPanel().setVisible(true);
    
        //Initialize FX Panel
        this.mediaRoot = new Group();
        this.mediaScene = new Scene(this.mediaRoot, 0, 0);
    
        //Open/prepare the file
        //String tutorialFilePath = new File("").getAbsolutePath() + DIRECTORY_PATH + "Tutorial.mp4";
        String tutorialFilePath = new File("").getAbsolutePath() + MEDIA_PATH + this.observer.getName() +"Tutorial.mp4";
        File mediaFile = new File(tutorialFilePath);
        this.tutorialVideo = new Media(mediaFile.toURI().toString());
    
        //Create the media player
        this.VideoPlayer = new MediaPlayer(this.tutorialVideo);  //Error here
        this.VideoPlayer.setAutoPlay(false);
    
        this.mediaViewer = new MediaView(this.VideoPlayer);
        this.mediaViewer.setFitHeight(this.mediaPanel.getPanelHeight());
        this.mediaViewer.setFitWidth(this.mediaPanel.getPanelWidth());
            ((Group)this.mediaScene.getRoot()).getChildren().add(this.mediaViewer);
    
        this.mediaPanel.getMediaPanel().setScene(this.mediaScene);
    }
    

    感谢所有帮助过的人!

    【讨论】:

    • 实际上,情况并非如此......线程是一个问题,但 NPE 正在发生,因为当您完全删除 JFXPanel 时 FX 工具包会关闭。见答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多