开发者

automatically causing a subclassed JPanel's resources to be released

Suppose I subclass JPanel, and my subclass uses a lot of memory.

What is the right way for me to design this class so that the memory resources are freed when my JPanel is used as a component in a larger system?

Seems like there's a few options:

  1. subclass finalize() (red flags all over the place -- the literature I've read says you shouldn't get into the finalizing business)
  2. add an explicit dispose() or destroy() or whatever, for consumers of my class to use
  3. add some kind of listener to my JPanel that gets notified when the parent gets disposed
  4. override some method of JPanel which will automatically get called when their parent window gets disposed

In the example below I used the finalize() option, which works but only when garbage collection gets called, and there are instances where I'd rather the cleanup happens when the JPanel is no longer needed.

Option #2 is nice, but then I have to rely on consumers to call this method, and the Swing philosophy seems to be just stick components into a window, and let all the components get destroyed when the window gets closed. So if my JPanel is inside a JTable in a JScrollPane in a JPanel in a JFrame, chances are, the consumer of my class isn't going to call my dispose() or destroy() method.

Options #3 or #4 would be my choice but I can't find anything that seems to apply here.

Any suggestions?

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);
    }   
}


The best solution is to add a HierarchyListener to the JPanel and then check for HierarchyEvent.DISPLAYABILITY_CHANGED (which get triggered when the parent dialog is shown and disposed) and then check for isDisplayable() to false which is the condition set when it is in the process of disposing.

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);

   }
}


Like you mentioned, don't call finalize(), this is just dangerous and hard to get right.

I've always added dispose methods that take care of listener cleanup and removing any memory intensive resources. I think the trick to doing this properly, is there should be a manager of some sort that handles destroying such objects.

If you're talking about more generic components that would be used in a more general framework this might not be the correct solution

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜