Thread.sleep()的意外行为

时间:2016-03-02 14:26:07

标签: java javafx

我构建了一个播放歌曲的简单程序。

import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import java.io.File;
import javax.swing.*;
import java.awt.*;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.application.Platform;
import javafx.scene.Group; 

public class Fade {
    private void initAndShowGUI() {
        // This method is invoked on Swing thread
        JFrame frame = new JFrame("FX");
        final JFXPanel fxPanel = new JFXPanel();
        frame.add(fxPanel);
        frame.setVisible(true);

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                initFX(fxPanel);
            }
        });
    }

    private void initFX(JFXPanel fxPanel) {
    // This method is invoked on JavaFX thread
        Group root = new Group(); 
        Scene scene = new Scene(root, 500, 500, true);
        fxPanel.setScene(scene);

        try {
            String bip = new File("./Sound/Welcome To The Show - L1-5.mp3").toURI().toString();
            Media hit = new Media(bip);
            MediaPlayer mediaPlayer = new MediaPlayer(hit);
            mediaPlayer.play();

            Thread.sleep(10000);
            System.out.println("Fade");
        } catch (Exception e) {
            System.out.println("Exception");
            System.out.println(e);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Fade().initAndShowGUI();
            }
        });
    }
}

然而,当运行此代码时,Thread.sleep(10000)在歌曲开始播放之前运行而不是开始播放的歌曲,然后10秒后fade将打印到控制台。我该如何解决这个问题?

2 个答案:

答案 0 :(得分:4)

您正在阻止JavaFX应用程序线程,因此它无法正常工作(可能包括处理媒体播放器的启动指令),直到您的方法完成。您永远不应该阻止此线程,因为它可以保证UI不响应。

在JavaFX中实现暂停的最简单方法是使用PauseTransition

MediaPlayer mediaPlayer = new MediaPlayer(hit);
mediaPlayer.play();

// never do this:
//Thread.sleep(10000);

PauseTransition pause = new PauseTransition(Duration.millis(10000));
pause.setOnFinished(e -> {
    System.out.println("Fade");
});
pause.play();

(顺便说一句,我认为你的真实应用程序有一些理由混合swing和JavaFX。否则你应该把它变成一个纯JavaFX应用程序。)

答案 1 :(得分:3)

MediaPlayer上操作是异步的。这解释了为什么在实际音乐开始之前打印"Fade"。来自the documentation

  

MediaPlayer的操作本质上是异步的。玩家不准备立即响应命令,直到其状态转换为MediaPlayer.Status.READY,这实际上通常发生在媒体预滚动完成时。然而,在状态为READY之前由玩家提出的某些请求将在输入该状态时生效。其中包括在play()转换之前调用pause()而无需调用stop()READY,以及设置任何autoPlaybalance },muteratestartTimestopTimevolume属性。

您可以通过轮询其status来控制玩家是否真正在玩游戏。来自play()(强调我的):

  

开始播放媒体。如果之前暂停,则播放将在暂停时恢复。如果停止播放,则从startTime开始播放。 实际播放时,状态将设置为MediaPlayer.Status.PLAYING

要在播放器开始播放时注册回调,您可以通过添加更改侦听器或通过调用onPlayingProperty直接设置事件处理程序来挂钩setOnPlaying(runnable)