автоматически вызывая освобождение ресурсов подкласса JPanel - PullRequest
4 голосов
/ 31 мая 2011

Предположим, я подкласс JPanel, и мой подкласс использует много памяти.

Как правильно спроектировать этот класс, чтобы освободить ресурсы памяти, когда мой JPanel используется в качестве компонента в более крупной системе?

Похоже, есть несколько вариантов:

  1. подкласс finalize() (красные флаги повсюду - литература, которую я читал, говорит, что вы не должны входить в завершающий бизнес)
  2. добавить явное dispose() или destroy() или что-то еще, чтобы потребители моего класса использовали
  3. добавить своего рода слушателя в мою JPanel, который получит уведомление, когда родитель будет удален
  4. переопределить некоторый метод JPanel, который будет автоматически вызываться при удалении их родительского окна

В приведенном ниже примере я использовал опцию finalize(), которая работает, но только когда вызывается сборщик мусора, и есть случаи, когда я предпочел бы очистку, когда JPanel больше не нужен.

Вариант № 2 хорош, но тогда я вынужден полагаться на то, что потребители будут вызывать этот метод, и философия Swing, похоже, просто вставляет компоненты в окно и позволяет всем компонентам разрушаться, когда окно закрывается. Поэтому, если мой JPanel находится внутри JTable в JScrollPane в JPanel в JFrame, скорее всего, потребитель моего класса не собирается вызывать мой метод dispose() или destroy().

Варианты №3 или №4 были бы моим выбором, но я не могу найти ничего подходящего здесь.

Есть предложения?

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class JPanelMemoryHog extends JPanel
{
    final private String title;
    final private Object space;

    public JPanelMemoryHog(String title)
    {
        super();
        this.title = title;
        this.space = new byte[5*1000*1000];
        setBorder(BorderFactory.createTitledBorder(title));
        setPreferredSize(new Dimension(300,200));
    }

    @Override protected void finalize()
    {
        System.out.println("finalized "+this.title);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("example");
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        JButton button = new JButton("create frame");
        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                createFrame();
            }
        });
        panel.add(button, BorderLayout.CENTER);
        frame.setContentPane(panel);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    private static int panelcount = 0;
    protected static void createFrame() {
        final String title = "panel"+(++panelcount);
        final JFrame frame = new JFrame(title);
        frame.setContentPane(new JPanelMemoryHog(title));
        frame.pack();
        frame.addWindowListener(new WindowAdapter() {
            @Override public void windowClosing(WindowEvent e) {
                System.out.println("closing "+title);
                frame.dispose();
            }
        });
        frame.setVisible(true);
    }   
}

Ответы [ 2 ]

4 голосов
/ 30 января 2013

Лучшее решение - добавить HierarchyListener в JPanel, а затем проверить на HierarchyEvent.DISPLAYABILITY_CHANGED (которое срабатывает, когда родительский диалог отображается и удаляется), а затем проверить на isDisplayable() в false, что является набором условийкогда он находится в процессе утилизации.

public void hierarchyChanged(HierarchyEvent e) {
   //check for Hierarchy event
   if(e.getChangeFlags() == HierarchyEvent.DISPLAYABILITY_CHANGED)
   {       
        //do the required action upon close
       if(!this.isDisplayable())                         
          Notifier.removeListener(this);

   }
}
0 голосов
/ 31 мая 2011

Как вы упомянули, не вызывайте finalize (), это просто опасно и трудно понять правильно.

Я всегда добавлял методы dispose, которые заботятся об очистке слушателя и удалении любых ресурсоемких ресурсов. Я думаю, хитрость в том, чтобы сделать это правильно, должен быть какой-то менеджер, который обрабатывает уничтожение таких объектов.

Если вы говорите о более общих компонентах, которые будут использоваться в более общей структуре, это может быть неправильным решением

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...