最近工做中碰到这个问题,用Java写的一个系统托盘,要求只能有一个实例,当再次启动程序的时候,须要激活并显示已经启动的实例。java
网上搜了一下,一个实例的问题网上已经有解决办法(使用文件锁),激活前一个实例的问题却没有头绪,有人说用Win32 API,但搜了好多,搜到的都是VB,VC++等来实现的,没有用Java的;还有一个方法是使用Socket,这个尝试了下,确实可行,但缺点是须要占用一个端口。app
这里我把两个问题写到一个例子里,供有须要的朋友参考:dom
其中:有一个系统托盘实例:SystemTray tray;一个窗体对象:JFrame frame;socket
在启动系统托盘的main()方法里,代码以下:ide
- public class AppTest {
- private JFrame frame; //窗体
- private SystemTray tray; //系统托盘
- private MyServer server; //服务端socket
- public AppTest() {
- init();
- }
- private void init(){
- //若是当前操做系统不支持系统托盘,则退出
- if(!SystemTray.isSupported()){
- JOptionPane.showMessageDialog(null, "对不起,当前操做系统不支持系统托盘!");
- System.exit(0);
- }
- tray = SystemTray.getSystemTray();
- Image p_w_picpath = null;
- try {
- p_w_picpath = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream("com/blog/icons.png"));
- } catch (IOException e) {
- JOptionPane.showMessageDialog(null, e.getMessage());
- System.exit(0);
- }
- final TrayIcon trayIcon = new TrayIcon(p_w_picpath);
- try {
- tray.add(trayIcon);
- } catch (AWTException e) {
- JOptionPane.showMessageDialog(null, e.getMessage());
- System.exit(0);
- }
- PopupMenu menu = new PopupMenu();
- MenuItem mi = new MenuItem("Exit");
- mi.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- frame.setVisible(false);
- frame.dispose();
- frame = null;
- tray.remove(trayIcon);
- tray = null;
- server.closeServer();
- System.exit(0);
- }
- });
- menu.add(mi);
- trayIcon.setPopupMenu(menu);
- frame = new JFrame("AppTest");
- frame.setSize(new Dimension(200, 200));
- frame.setVisible(true);
- }
- /**
- * 显示/隐藏 主窗体
- * */
- public void showHideFrame(boolean isVisible){
- frame.setVisible(isVisible);
- frame.setExtendedState(JFrame.NORMAL);
- }
- /**
- * 注入server对象,关闭server时使用
- * @param server
- */
- public void setServerSocket(MyServer server){
- this.server = server;
- }
- //检查是否得到锁,true:得到锁,说明是第一次执行;false:没有取得锁,说明已经有一个程序在执行
- public static boolean checkLock() {
- FileLock lock = null;
- RandomAccessFile r = null;
- FileChannel fc = null;
- try {
- // 在临时文件夹建立一个临时文件,锁住这个文件用来保证应用程序只有一个实例被建立.
- File sf = new File(System.getProperty("java.io.tmpdir") + "lock.single");
- sf.deleteOnExit();
- sf.createNewFile();
- r = new RandomAccessFile(sf, "rw");
- fc = r.getChannel();
- lock = fc.tryLock();
- if (lock == null||!lock.isValid()) {
- // 若是没有获得锁,则程序退出.
- // 没有必要手动释放锁和关闭流,当程序退出时,他们会被关闭的.
- return false;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return true;
- }
- public static void main(String[] args) {
- //检查文件锁,确保只有一个实例运行
- if(!checkLock()){
- //告知上一个程序激活主窗口
- try {
- new Socket(InetAddress.getLocalHost(),60098);
- } catch (Exception e) {
- e.printStackTrace();
- }
- //退出当前程序
- System.exit(0);
- }
- AppTest app = new AppTest();
- new MyServer(app);
- }
- static class MyServer{
- private ServerSocket server;//当前的socket
- private AppTest tray; //保存的前一个托盘实例
- public MyServer(AppTest tray) {
- this.tray = tray;
- tray.setServerSocket(this);
- initServerSocket();
- }
- private void initServerSocket(){
- try {
- server = new ServerSocket(60098);
- while(true){
- if(server.isClosed()){
- break;
- }
- //若是监听到一个socket链接,说明程序启图再次打开一个实例,此时显示前一个窗体
- Socket socket = server.accept();
- tray.showHideFrame(true);
- socket.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public void closeServer(){
- try {
- server.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }