JavaFX重复调用stage.show()与mediaPlayer.play()失效问题求助
问题:JavaFX通知首次正常,后续重复触发失效
我需要在Windows右下角显示带动画和音效的通知,首次启动Test.main()时功能完全正常,但后续通过定时任务重复触发播放动画和音效时失效。相关代码如下,求排查解决:
Test.java
public class Test { public static void main(String[] args) { ScheduledExecutorService executor = Executors.newScheduledThreadPool(4); executor.scheduleAtFixedRate(new NotificationRunnable(), 0, 2 * 60, TimeUnit.SECONDS); executor.scheduleAtFixedRate(new NotificationRunnable(), 0, 4 * 60, TimeUnit.SECONDS); executor.scheduleAtFixedRate(new NotificationRunnable(), 0, 9 * 60, TimeUnit.SECONDS); executor.scheduleAtFixedRate(new NotificationRunnable(), 0, 13 * 60, TimeUnit.SECONDS); //Launching application first time NotificationApp.runFromScheduledExecutor(); } }
NotificationRunnable.java
public class NotificationRunnable implements Runnable{ @Override public void run() { Platform.runLater(() -> { NotificationApp.playAnimation(); }); System.out.println("Done"); } }
NotificationApp.java
public class NotificationApp extends Application { public static void main(String[] args) { launch(args); } static Stage primaryStage = null; static MediaPlayer mediaPlayer = null; @Override public void start(Stage primaryStage) { // Create a custom dialog with an ImageView Image gifImage = new Image(String.valueOf(new File("img/giphy.gif"))); // Replace with your GIF file path ImageView gifImageView = new ImageView(gifImage); Pane pane = new Pane(gifImageView); Scene scene = new Scene(pane); // Set stage properties primaryStage.initStyle(StageStyle.TRANSPARENT); // Hide the window decoration primaryStage.setAlwaysOnTop(true); // Determine screen dimensions double screenWidth = Screen.getPrimary().getVisualBounds().getWidth(); double screenHeight = Screen.getPrimary().getVisualBounds().getHeight(); double stageWidth = gifImage.getWidth(); double stageHeight = gifImage.getHeight(); // Set the stage position to the right corner double xOffset = screenWidth - stageWidth; double yOffset = screenHeight - stageHeight; primaryStage.setX(xOffset); primaryStage.setY(yOffset); primaryStage.setScene(scene); this.primaryStage = primaryStage; Media sound = new Media(new Test().getClass().getResource("/snd/Notification.mp3").toExternalForm()); mediaPlayer = new MediaPlayer(sound); //Play animation and Sound during application start Platform.runLater(() -> { playAnimation(); }); } public static void playAnimation(){ Platform.runLater(() -> { mediaPlayer.play(); primaryStage.show(); }); // Schedule closing the stage after 5 seconds ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.schedule(() -> { Platform.runLater(() -> { mediaPlayer.stop(); primaryStage.close(); }); }, 5, TimeUnit.SECONDS); } public static void runFromScheduledExecutor() { Application.launch(NotificationApp.class); } }
问题原因与修复方案
核心问题
- MediaPlayer状态未重置:首次播放后,MediaPlayer的播放位置停在音频末尾,后续调用
play()不会从头开始播放。 - Stage重复关闭/显示的状态冲突:Stage关闭后再次调用
show()可能引发状态异常,导致动画无法正常显示。 - 定时线程池资源泄漏:每次调用
playAnimation()都创建新的ScheduledExecutorService,未回收线程资源。
修复步骤
重置MediaPlayer播放位置
每次播放前将音频进度重置到起始位置,确保从头播放:public static void playAnimation(){ Platform.runLater(() -> { mediaPlayer.seek(Duration.ZERO); // 重置到音频开头 mediaPlayer.play(); primaryStage.show(); }); // ... 其他代码 }改用Stage.hide()替代close()
避免反复关闭Stage,改为隐藏,减少状态异常:scheduler.schedule(() -> { Platform.runLater(() -> { mediaPlayer.stop(); primaryStage.hide(); // 隐藏而非关闭 }); }, 5, TimeUnit.SECONDS);复用全局定时线程池
全局维护一个线程池,避免重复创建导致的资源泄漏:// 在NotificationApp中添加全局线程池 private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); public static void playAnimation(){ Platform.runLater(() -> { mediaPlayer.seek(Duration.ZERO); mediaPlayer.play(); primaryStage.show(); }); // 使用全局线程池 scheduler.schedule(() -> { Platform.runLater(() -> { mediaPlayer.stop(); primaryStage.hide(); }); }, 5, TimeUnit.SECONDS); } // 程序退出时关闭线程池 @Override public void stop() throws Exception { scheduler.shutdown(); super.stop(); }统一资源加载方式
图片路径改用和音频一致的类加载器方式,避免文件路径问题:Image gifImage = new Image(NotificationApp.class.getResource("/img/giphy.gif").toExternalForm());
内容的提问来源于stack exchange,提问作者Lalit k
相关产品推荐
相关产品推荐

