重用 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()
,这样如果发生异常,您将确切地知道发生了什么以及在哪里。
我有一个我和我朋友制作的程序,它的功能是定时器和闹钟。它会在您启动计时器时播放声音并显示图像,并在计时器结束时播放另一个声音和图像。它一直运行良好(或多或少),但我的朋友最近切换到 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()
,这样如果发生异常,您将确切地知道发生了什么以及在哪里。