重用 AudioInputStream

Reusing an AudioInputStream

我有一个我和我朋友制作的程序,它的功能是定时器和闹钟。它会在您启动计时器时播放声音并显示图像,并在计时器结束时播放另一个声音和图像。它一直运行良好(或多或少),但我的朋友最近切换到 Linux 并且有一些更具交互性的声音控制器,这导致我们发现该程序的一个问题:每次播放声音时,它都会创建一个全新的输入流,不会被重用,并且在程序完全关闭之前不会消失。我想学习如何修复这个糟糕的设计,而且当我朋友试图多次使用计时器而不关闭程序时,它也会导致我朋友的问题。我相信解决方法是让所有声音都通过一个输入流播放(如果有人对 Java 和 Linux 的交互有更多了解,请纠正我)。我尝试简单地将 AudioInputStream 设置为全局变量并在每次使用前重置它,但这会导致图像和声音完全停止工作,我不知道为什么。下面是我当前和有缺陷的代码按下按钮时执行的操作。接下来是有效但无效的代码。

private void buttonActionPerformed(java.awt.event.ActionEvent evt) {                                            
        
        boolean needNewThread = false;
        if (imgWindow.getIcon() == null) {
            needNewThread = true;
        }
        timeUpLabel.setText(" ");
        BufferedImage buffImg = null;
        try{
            globalAudioIn.reset();
            URL url = this.getClass().getResource("/EvilManiMani.wav");
            globalAudioIn = AudioSystem.getAudioInputStream(url);
            Clip clip = AudioSystem.getClip();
            clip.open(globalAudioIn);
            clip.start();
            buffImg = ImageIO.read(getClass().getResource("/images/cloudWait.png"));
            imgWindow.setIcon(new ImageIcon(buffImg));
            System.out.println(buffImg.toString());
        } catch (Exception e){
            System.out.println(e.getMessage());
        }
        Integer inputTime = Integer.parseInt(timeTextField.getText());
        timerLabel.setText(inputTime + ":00");
        if(needNewThread) {
            t = new Timer(1000, new ActionListener (){
                @Override
                public void actionPerformed(ActionEvent ae){
                    String[] minsAndSeconds = timerLabel.getText().split(":");
                    boolean timesUp = false;
                    if(minsAndSeconds[0].startsWith("-")) {
                        timesUp = true;
                        String temp = minsAndSeconds[0].substring(1);
                        minsAndSeconds[0] = temp;
                    }
                    Integer minutes = Integer.parseInt(minsAndSeconds[0]);
                    Integer seconds = Integer.parseInt(minsAndSeconds[1]);
                    seconds += (minutes*60);
                    if(seconds > 0 && !timesUp){
                        minutes = --seconds/60;
                        seconds %= 60;
                        if(seconds >= 10) {
                            timerLabel.setText(minutes + ":" + seconds);
                        }else {
                            timerLabel.setText(minutes + ":0" + seconds);
                        }
                    }else if(seconds > 0 && timesUp) {
                        minutes = ++seconds/60;
                        seconds %= 60;
                        if(seconds >= 10) {
                            timerLabel.setText("-" + minutes + ":" + seconds);
                        }else {
                            timerLabel.setText("-" + minutes + ":0" + seconds);
                        }
                    }else if (seconds == 0){
                        timerLabel.setText("-0:01");
                        BufferedImage bufferedImg = null;
                        try {
                            globalAudioIn.reset();
                            URL url = this.getClass().getResource("/YouWin!.wav");
                            globalAudioIn = AudioSystem.getAudioInputStream(url);
                            Clip clip = AudioSystem.getClip();
                            clip.open(globalAudioIn);
                            clip.start();
                            bufferedImg = ImageIO.read(getClass().getResource("/images/drinkyMattPog.png"));
                            imgWindow.setIcon(new ImageIcon(bufferedImg));
                            timeUpLabel.setText("Time's up");
                        } catch (Exception e) {
                            System.out.println(e.getMessage());
                        }
                    }
                }
            });
            t.setRepeats(true);
            t.start();
        }
    }

有效但无效:

   private void buttonActionPerformed(java.awt.event.ActionEvent evt) {                                            
        
        boolean needNewThread = false;
        if (imgWindow.getIcon() == null) {
            needNewThread = true;
        }
        timeUpLabel.setText(" ");
        BufferedImage buffImg = null;
        try{
            URL url = this.getClass().getResource("/EvilManiMani.wav");
            AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
            Clip clip = AudioSystem.getClip();
            clip.open(audioIn);
            clip.start();
            buffImg = ImageIO.read(getClass().getResource("/images/cloudWait.png"));
            imgWindow.setIcon(new ImageIcon(buffImg));
            System.out.println(buffImg.toString());
        } catch (Exception e){
            System.out.println(e.getMessage());
        }
        Integer inputTime = Integer.parseInt(timeTextField.getText());
        timerLabel.setText(inputTime + ":00");
        if(needNewThread) {
            t = new Timer(1000, new ActionListener (){
                @Override
                public void actionPerformed(ActionEvent ae){
                    String[] minsAndSeconds = timerLabel.getText().split(":");
                    boolean timesUp = false;
                    if(minsAndSeconds[0].startsWith("-")) {
                        timesUp = true;
                        String temp = minsAndSeconds[0].substring(1);
                        minsAndSeconds[0] = temp;
                    }
                    Integer minutes = Integer.parseInt(minsAndSeconds[0]);
                    Integer seconds = Integer.parseInt(minsAndSeconds[1]);
                    seconds += (minutes*60);
                    if(seconds > 0 && !timesUp){
                        minutes = --seconds/60;
                        seconds %= 60;
                        if(seconds >= 10) {
                            timerLabel.setText(minutes + ":" + seconds);
                        }else {
                            timerLabel.setText(minutes + ":0" + seconds);
                        }
                    }else if(seconds > 0 && timesUp) {
                        minutes = ++seconds/60;
                        seconds %= 60;
                        if(seconds >= 10) {
                            timerLabel.setText("-" + minutes + ":" + seconds);
                        }else {
                            timerLabel.setText("-" + minutes + ":0" + seconds);
                        }
                    }else if (seconds == 0){
                        timerLabel.setText("-0:01");
                        BufferedImage bufferedImg = null;
                        try {
                            URL url = this.getClass().getResource("/YouWin!.wav");
                            AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
                            Clip clip = AudioSystem.getClip();
                            clip.open(audioIn);
                            clip.start();
                            bufferedImg = ImageIO.read(getClass().getResource("/images/drinkyMattPog.png"));
                            imgWindow.setIcon(new ImageIcon(bufferedImg));
                            timeUpLabel.setText("Time's up");
                        } catch (Exception e) {
                            System.out.println(e.getMessage());
                        }
                    }
                }
            });
            t.setRepeats(true);
            t.start();
        }
    }                         

谢谢!此外,欢迎对代码提出任何建设性的批评,无论是否与问题相关。

在调用 clip.start() 之前,添加一个侦听器以关闭 Clip 和 AudioInputStream:

clip.open(audioIn);
clip.addLineListener(e -> {
    if (e.getType().equals(LineEvent.Type.STOP)) {
        clip.close();
        try {
            audioIn.close();
        } catch (IOException e) {
            System.err.println(e);
        }
    }
});
clip.start();

既然你提出了建设性的批评意见:千万不要写catch (Exception)。您不想捕获 RuntimeException 或其子类,因为它们通常表明程序员的错误需要暴露和修复,而不是掩盖。在您的情况下,您应该改用 catch (LineUnavailableException | IOException e)

您的 catch 块不应打印 e.getMessage()。相反,使用 e.printStackTrace(),这样如果发生异常,您将确切地知道发生了什么以及在哪里。