Приветствую, Джаварашовцы!
Столкнулся с проблемой, нужен совет сослуживцев.
Мне поступил небольшой заказ на разработку простенькой детской игры. Взялся за это дело не раздумывая, т.к. наконец-то появилась возможность сделать что-то полезное, да еще и денежку за это получить.
Суть в следующем - на экране вопрос, под вопросом три варианта ответа в виде картинок. Пользователь ответил правильно - окно перерисовывается, появляется новый вопрос и новые картинки-ответы. Все это реализуется очень просто, но есть один нюанс - при смене вопроса и картинок загрузка ОЗУ неприлично возрастает, примерно на 2-3 Мб при каждом новом вопросе. При первоначальном запуске приложение занимает ~20Мб памяти, затем после >20 переключений вопросов возрастает до 60-65 Мб, что, как я понимаю, неприлично много для такого простого приложения.
Анализировал эту проблему с помощью Visual VM, выяснил, что GC начинает работать только когда память кучи приближается к концу.
Опытным путем выяснил, что память расходуется в этой части кода (осторожно, говнокод!):
private static void drawNewImages(){
imagePanel.removeAll();
for(String fileName : DataParser.Series1Images.get(CurrentQuestion)){
ImageLabel label = new ImageLabel(fileName);
imagePanel.add(label);
}
imagePanel.revalidate();
}
Собственно здесь происходит удаление всех старых картинок-ответов и расположение новых. Картинки реализованы через JLabel.
DataParser.Series1Images содержит имена файлов с картинками-ответами.
Привожу код класса ImageLabel:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by Vimper on 09.03.2015.
*/
public class ImageLabel extends JLabel {
public static final int DEFAULT_IMAGE_WIDTH = 300;
public static final int DEFAULT_IMAGE_HEIGHT = 200;
private String fileName = "";
private MouseListener listener;
public ImageLabel(String iconName){
super();
try (InputStream inputStream = getClass().getResourceAsStream(MusicPlayer.RESOURCES_PATH + iconName);)
{
Image img = ImageIO.read(inputStream);
this.fileName = iconName;
ImageIcon icon = new ImageIcon(img.getScaledInstance(DEFAULT_IMAGE_WIDTH_SQUARE,DEFAULT_IMAGE_HEIGHT,0));
setIcon(icon);
}
catch (IOException e){
e.printStackTrace();
}
listener = new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
if(MusicPlayer.currentAudioIs(MainFrame.QUESTION_MP3))
return;
if(fileName.contains(TRUE_ANSWER)){
setBorder(BorderFactory.createMatteBorder(2,2,2,2,Color.green));
endOfQuestion();
}
else{
setBorder(BorderFactory.createMatteBorder(2,2,2,2,Color.red));
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
// если курсор на картинке - меняем окантовку.
@Override
public void mouseEntered(MouseEvent e) {
setBorder(BorderFactory.createMatteBorder(2,2,2,2,Color.gray));
}
// курсор покинул картинку - возвращаем прежнюю окантовку.
@Override
public void mouseExited(MouseEvent e) {
setBorder(BorderFactory.createEmptyBorder());
}
};
addMouseListener(listener);
}
public void endOfQuestion(){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
while(!MusicPlayer.musicComplete()) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
MusicPlayer.setDefaultFileName();
MainFrame.NextQuestion();
}});
}
}
Здесь если нажата верная картинка - переходим к новому вопросу через метод endOfQuestion(), из которого впоследствии переходим к drawNewImages():
public static void NextQuestion(){
CurrentQuestion++;
if(CurrentQuestion == DataParser.Questions.size())
CurrentQuestion = 0;
drawNewQuestion();
drawNewImages();
}
Корректно ли реализовано обновление панели с изображениями? Какие у кого есть соображения по поводу затрат ОЗУ в данном случае? Если нужно, выложу полностью исходники.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ