今天在做一款基于Java Swing界面的烟花游戏时,发现在播放音频的过程中界面异常卡顿,查看任务管理器,发现GPU占用几乎高达百分之百,于是立刻想到应该是由于循环内创建对象导致的内存溢出
音频播放类代码如下 BackGroundSound
// 音频播放类
import java.applet.Applet;
import java.applet.AudioClip;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Optional;
public class BackGroundSound {
public void setSoundState(String filePath,String state) throws MalformedURLException {
URL url = new File(filePath).toURL();
AudioClip audioClip = Applet.newAudioClip(url);
if(state.equals("start")){
audioClip.play();
}else if (state.equals("stop")){
audioClip.stop();
}
}
}
调用如下:
//按钮监听事件
btnStart.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//System.out.println("button被按下了");
btnStop.setDoubleBuffered(true);
new Thread(new Runnable() {
@Override
public void run() {
state = 1;
while (state==1) {
try {
Thread.sleep(200);
if(fireworks.getY()==595||fireworks1.getY()==580||fireworks2.getY()==601||fireworks3.getY()==616){
new BackGroundSound().
backGroundSound.setSoundState("sounds/9800.wav","start");
new BackGroundSound().
backGroundSound.setSoundState("sounds/y939.wav","stop");
}
if(fireworks.getY()==190||fireworks1.getY()==240||fireworks2.getY()==133||fireworks3.getY()==208){
new BackGroundSound().
backGroundSound.setSoundState("sounds/9800.wav","stop");
new BackGroundSound().
backGroundSound.setSoundState("sounds/y939.wav","start");
}
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
} catch (MalformedURLException ex) {
throw new RuntimeException(ex);
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
repaint();
}
});
}
}
}).start();
}
});
在上述的判断代码中,看上去每个if语句里创建了2个对象,但实际上调用的BackGroundSound 类的代码中又创建了2个对象,相当于一次判断中创建了4个对象,这还不算while循环,于是对代码进行一番爆改,将BackGroundSound提取出来作为成员变量,按钮监听整改代码如下 :
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.MalformedURLException;
import java.util.Random;
public class FireworksWindow extends JFrame {
/*
具体代码省略
*/
...
BackGroundSound backGroundSound = new BackGroundSound();
public FireworksWindow(){
...
btnStart.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//System.out.println("button被按下了");
btnStop.setDoubleBuffered(true);
new Thread(new Runnable() {
@Override
public void run() {
state = 1;
while (state==1) {
try {
Thread.sleep(200);
if(fireworks.getY()==595||fireworks1.getY()==580||fireworks2.getY()==601||fireworks3.getY()==616){
backGroundSound.setSoundState("sounds/9800.wav","start");
backGroundSound.setSoundState("sounds/y939.wav","stop");
}
if(fireworks.getY()==190||fireworks1.getY()==240||fireworks2.getY()==133||fireworks3.getY()==208){
backGroundSound.setSoundState("sounds/9800.wav","stop");
backGroundSound.setSoundState("sounds/y939.wav","start");
}
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
} catch (MalformedURLException ex) {
throw new RuntimeException(ex);
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
repaint();
}
});
}
}
}).start();
}
});
}
}
同样,对BackGroundSound类中的代码进行如下整改:
import java.applet.Applet;
import java.applet.AudioClip;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Optional;
public class BackGroundSound {
/*
将URL和AudioCilp 对象提取作为成员变量
*/
private URL url;
private AudioClip audioClip;
public void setSoundState(String filePath,String state) throws MalformedURLException {
/*
调用Optional类中的方法判断对象是否存在,如果不存在,则创建
*/
boolean urlObj = Optional.ofNullable(url).isPresent();
boolean audioClipObj = Optional.ofNullable(audioClip).isPresent();
if(!urlObj&&!audioClipObj){
url = new File(filePath).toURL();
audioClip = Applet.newAudioClip(url);
}
if(state.equals("start")){
audioClip.play();
}else if (state.equals("stop")){
audioClip.stop();
}
}
}
这样一来,调用setSoundState()方法,能每个保证只创建一次,便解决了循环创建对象导致的CPU和内存占用过高的问题。