0

I have an FX Application where, from the beginning, it starts playing music, which works. Now I want that when I open a method to play another sound on top of it.

I coded the second sound like the first but it isn't working. I tried making a new Thread but no change. The new sound is actually playing somehow. Sometimes it doesn't play at all. Sometimes entirely and sometimes for just one sec.

Method with new sound

    public void showFight(int fighterLeft, int fighterRight) throws InterruptedException {

        //Some code

        new Thread(() -> {
            music2();
        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(3000L);
            } catch (InterruptedException e) {
            }
            Platform.runLater(() -> {
                //FadeIn();
                FightPane.setVisible(false);
            });
        }).start();

    }

    public static void music2() {
        Media hit2 = new Media(JavaFXApplicationStratego.class.getResource("/Sounds/fight.mp3").toString());
        MediaPlayer mediaPlayer2 = new MediaPlayer(hit2);
        mediaPlayer2.play();
    }

First Sound

public static void music() {
        String bip = "/stopen.mp3";
        Media hit = new Media(JavaFXApplicationStratego.class.getResource("/Sounds/stopen.mp3").toString());
        MediaPlayer mediaPlayer = new MediaPlayer(hit);
        mediaPlayer.play();
    }
Abra
  • 19,142
  • 7
  • 29
  • 41
mip42
  • 65
  • 6
  • Actually even the First Music isn't working properly, when I start the Application it sometimes starts to play sometimes don't and sometimes for just one second. But that's another Problem – mip42 Jan 26 '20 at 04:12
  • so what you wish to get done is play simultaneous sounds executing from inside the thread, right? if so, then take a peek at this [SO link](https://stackoverflow.com/questions/42798276/java-multi-threading-sound-clips-to-play-at-same-time) – EvOlaNdLuPiZ Jan 26 '20 at 04:13

1 Answers1

1

You're not maintaining a strong reference to the MediaPlayer. This means the instance is eligible for garbage collection as soon as the call to #music() returns (same problem w.r.t. #music2()). Once garbage collected, the media will stop playing. Since garbage collection cycles do not happen at predetermined times, but rather as needed, you see different behavior between different instances of your application. The fix is to store the MediaPlayer instances somewhere they'll be strongly reachable, such as in a field of your class (assuming the instance of your class is also strongly reachable).

There's also no reason, based on what you've provided in your question, to use threads. Playing music in JavaFX is already asynchronous. And as for performing an action on the JavaFX Application Thread at some later time it's best to use the animation API. The JavaFX periodic background task Q&A shows examples of this. For instance:

PauseTransition pt = new PauseTransition(Duration.seconds(3));
pt.setOnFinished(e -> FlightPane.setVisible(false));
pt.play();

Note: Assuming FlightPane is the name of a field it should ideally be named flightPane. See Java naming conventions.

Slaw
  • 37,820
  • 8
  • 53
  • 80