详细步骤
例行说明
-
Debug 开篇引言——越往后越难,情况越多越复杂,坐稳啦
-
V1.5.1
中switchCase & graphicsImageSet()
的代码解释下有引出一个 BUG
每 paint 一次,就会初始化一次按钮的贴图,重复的初始化,导致无缘无故地消耗内存,属于代码逻辑错误
具体步骤
- 正确的处理方式,
new
一个MyButton
时贴图初始化一次即可,paint
的时候把图贴上去就行,这样就可以避免重复初始化导致过多的内存消耗 - 优化过程排除干扰项的说明请见 Option
代码分析
MyButton
初始化setImageAndWavByName()
初始化按钮路径modifyImageByType()
根据按钮类型对按钮进行修改setImageByType()
设置图片与按钮大小相适应
注:这里一些方法只是重命名而已,方法体内代码做了调整,并没有过多修改
就如之前所说,这里只贴核心代码,详细请见 V1.7.1 MyButton
MyButton(KeyboardPiano kp, String text, String name) {
setImageAndWavByName(name);
}
public void setImageAndWavByName(String name) { //UpName
modifyImageByType(imageName.charAt(TYPE_INDEX));
}
private void modifyImageByType(int type) { //char type actually
switch(type) {
case A :
setImageByType(A_TYPE, 2, 2);
break;
}
}
private void setImageByType(int type, int widthMinus, int heightMinus) {
imageUp.setImage(imageUp.getImage().getScaledInstance(type-widthMinus, HEIGHT-heightMinus, Image.SCALE_DEFAULT));
imageDown.setImage(imageDown.getImage().getScaledInstance(type-widthMinus, HEIGHT-heightMinus, Image.SCALE_DEFAULT));
}
其实这些代码可以写在一个方法体内,但这样代码太臃肿,这也是为什么要用多个方法体来做一件事的原因
同时博主对方法重命名,其实意在体现命名规范的重要性——见名知意!!(前面的命名方式实在不堪入目(●′ω`●))
paintComponent()
画组件fillRectByType()
根据类型处理按钮圆角
protected void paintComponent(Graphics g) {
fillRectByType(g2d, imageName.charAt(TYPE_INDEX));
}
private void fillRectByType(Graphics2D g2d, int type) { //char actually
switch(type) {
case A :
g2d.fillRoundRect(0, 0, A_TYPE, HEIGHT, ARC_WIDTH, ARC_HEIGHT); //make Rectangle more beautiful
break;
}
}
细心的童鞋会发现,其实
fillRectByType
就是从setImageByType
分离出来的,这样初始化 & 重画的工作分开,也就减少了内存的压力
-
最后贴几张图看一下优化的效果(读者也可自行比较验证)
-
img1 程序初始化所占内存 80+ M
-
img2
V1.7
1000+ 次按键后,内存占用 290+ M
-
img3
V1.7.1
贴图优化后,1000+ 次按键后,内存占用 120+ M
由此可见,内存上做了很大的优化,但并未做到 0 泄露,有待进一步的优化
Option
-
控制变量法——单一变量原则
测试过程去除音频干扰,避免多变量影响内存而混淆视听,这个是 Debug/Test 过程常用的方法 -
做法很简单,直接把
MusicPlayer
注释即可
@Override
protected void paintComponent(Graphics g) {
if(this.isSelected()) {
g2d.drawImage(imageDown.getImage(), 1, 1, null);
/*
* play music once
*/
// new Thread(new MusicPlayer(getType(), wavPath)).start();
} else { //default is Up
g2d.drawImage(imageUp.getImage(), 1, 1, null);
}
}