简体   繁体   中英

Java detect when application is closing

I learned Java for about 1 year some years ago. Now I wanted to go back to it, but my skills got a bit rusty. So I'm using Eclipse with the WindowBuilder to make an easy Form Application to get started again. I wanted to get a popup window when I exit the application because in future projects I need to execute some code when the application is being exited by another way than my own exit button (for example via the red cross or Alt+F4).

So this is my code so far:

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;


public class Mainframe {

private JFrame frame;

/**
 * Launch the application.
 */
public static void main(String[] args) {


    Runtime.getRuntime().addShutdownHook(new Thread()
    {
        @Override
        public void run()
        {
            JOptionPane.showConfirmDialog(null, "Do you", "Message", 
                    JOptionPane.YES_NO_OPTION);
            MessageBox.infoBox("YOUR INFORMATION HERE", "TITLE BAR MESSAGE");
        }
    });

    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                Mainframe window = new Mainframe();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });

}

/**
 * Create the application.
 */
public Mainframe() {
    initialize();
}

/**
 * Initialize the contents of the frame.
 */
private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 450, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JButton btnNewButton = new JButton("New button");
    btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            System.exit(0);


        }
    });
    frame.getContentPane().add(btnNewButton, BorderLayout.SOUTH);
}



}

I used the code for the "when the Application is being exited" from this example, but no matter how I close it, no "Messagebox is appearing". When I use the code for the MessageBoxes directly after the main void, the MessageBoxes appear, so I guess I missplaced the ShutdownHook.

I would really appreciate if anybody can help me fix this problem.

I'm a little late to the party here but figured I'd add my 2 cents. I think it's best to use a static class that allows for shutdown listeners. It's much less complicated, and allows for checking if the JVM is currently shutting down (ex: to hide log messages). Here's the implementation I went with:

import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

public enum ShutdownNotifier {
    INSTANCE;

    private static final Class<?> THIS_CLASS = new Object() {
    }.getClass().getEnclosingClass();
    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(THIS_CLASS);

    private Set<AutoCloseable> _listeners;
    private CompletableFuture<Void> _shutdownFuture;

    public boolean isShuttingDown() {
        return getShutdownFuture().isDone();
    }

    public boolean addListener(AutoCloseable listener) {
        if (listener == null)
            return false;
        var listeners = this.getListeners();
        boolean added;
        synchronized (listeners) {
            added = listeners.add(listener);
        }
        if (this.isShuttingDown()) {
            this.notifyListeners();
            return true;
        }
        return added;
    }

    public boolean removeListener(AutoCloseable listener) {
        if (listener == null)
            return false;
        var listeners = getListeners(false);
        if (listeners == null)
            return false;
        synchronized (listeners) {
            return listeners.remove(listener);
        }
    }

    private Set<AutoCloseable> getListeners() {
        return getListeners(true);
    }

    private Set<AutoCloseable> getListeners(boolean create) {
        if (_listeners == null && create)
            synchronized (this) {
                if (_listeners == null && create)
                    _listeners = new HashSet<>();
            }
        return _listeners;
    }

    private CompletableFuture<Void> getShutdownFuture() {
        if (_shutdownFuture == null)
            synchronized (this) {
                if (_shutdownFuture == null) {
                    var future = new CompletableFuture<Void>();
                    future.whenComplete((v, t) -> {
                        notifyListeners();
                    });
                    try {
                        Runtime.getRuntime().addShutdownHook(new Thread(() -> future.complete(null)));
                    } catch (IllegalStateException e) {
                        future.complete(null);
                    }
                    _shutdownFuture = future;
                }
            }
        return _shutdownFuture;
    }

    private void notifyListeners() {
        var listeners = getListeners(false);
        if (listeners == null)
            return;
        while (true) {
            AutoCloseable listener;
            synchronized (listeners) {
                var iter = listeners.iterator();
                if (!iter.hasNext())
                    break;
                listener = iter.next();
                iter.remove();
            }
            try {
                listener.close();
            } catch (Throwable t) {
                logger.warn("shutdown listener invocation failed", t);
            }
        }
    }

    
}

The shutdown hook is meant to perform certain actions (such as closing database connections and shutting down threads) once the application has been shut down (be it by a System.exit call or a kill signal from the OS). It is not meant to be used for these kinds of dialogs.

You will want to add a WindowListener to your JFrame , and perform an action on the windowClosing and/or windowClosed events. In this listener, you can then display a dialog or whatever you wish.

If you wish to be able to override the closing of the window, you can find details on how to do so on this question .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM