使用 OSXAdapter 的 JAR Bundler 导致应用程序滞后或终止 [英] JAR Bundler using OSXAdapter causing application to lag or terminate

查看:24
本文介绍了使用 OSXAdapter 的 JAR Bundler 导致应用程序滞后或终止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个简单的 Java 应用程序,在连续 10 秒的时间内每秒钟向 JTable 添加一个新行.它由三个类组成.

I've created a simple Java application that each second for for 10 seconds consecutive seconds adds a new row to a JTable. It consists of three classes.

程序启动后调用的主类

public class JarBundlerProblem {
    public static void main(String[] args)
    {
        System.err.println("Initializing controller");
        new Controller();
    }
}

创建 GUI 并通过 doWork()

public class Controller {
    public Controller()
    {
        doWork(null);
    }
    public static void doWork(String s)
    {
        GUI gui = new GUI();
        
        for (int i=0; i<10; i++)
        {
            gui.addRow("Line "+(i+1));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

最后是图形用户界面

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class GUI {
    private JFrame frame = new JFrame();
    private DefaultTableModel model = new DefaultTableModel();
    private JTable table = new JTable(model);
    private JScrollPane pane = new JScrollPane(table);
    
    public GUI()
    {
        model.addColumn("Name");
        
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(pane);
        frame.pack();
        frame.setVisible(true);
    }
    public void addRow(String name)
    {
        model.addRow(new Object[]{name});
    }
}

由于我正在为 OS X 开发,并且我需要能够将我的应用程序与某种文件类型相关联(比如 .jarbundlerproblem),我必须捆绑我的 JAR 文件到 APP 使用 Apple Jar Bundler.我成功地做到了这一点,我的应用程序打开,数到十,每秒写出一次.

Since I'm developing for OS X, and I need to be able to associate my application with a certain file type (let's say .jarbundlerproblem), I have to bundle my JAR file into an APP using Apple Jar Bundler. I have done this successfully, my application opens, counts to ten, writing out each second.

默认情况下,双击 .jarbundlerproblem 并将文件与我的应用程序相关联,不会将我双击的文件作为参数传递给应用程序.显然,这只是 OS X 上的 Java 工作.

By default, double-clicking a .jarbundlerproblem, and associating the file with my application, will not pass the file I double-clicked as an argument to the application. Apparently, this is just Java on OS X works.

因为我需要能够看到双击的文件,所以我使用 OSXAdapter 这是 Apple 为此目的制作的 Java 库.这一点,我通过改变我的 Controller 类的构造函数并添加了另一个方法 registerForMacOSXEvents() 来实现:

Since I need to be able to see what file was double-clicked, I'm using OSXAdapter which is a Java library made by Apple for the purpose. This, I've implemented by altering the constructor of my Controller class and added another method registerForMacOSXEvents():

public Controller()
{
    registerForMacOSXEvents();
    //doWork(null);
}
public void registerForMacOSXEvents() {
    try {
        OSXAdapter.setFileHandler(this, getClass().getDeclaredMethod("doWork", new Class[] { String.class }));
    } catch (Exception e) {
        System.err.println("Error while loading the OSXAdapter:");
        e.printStackTrace();
    }
}

但是在这个(小)修改之后,我的应用程序开始起作用了.有时,它没有打开,即使我在控制台中看到它刚刚启动(Initializing controller 已写入),但经过几次尝试,它最终会启动,但窗口将前 10 秒完全空白,之后将添加 10 行.

But after this (minor) modification, my application starts acting up. Sometimes, it doesn't open, even though I can see in the Console that it just started (Initializing controller is written), but after a few attempts, it will eventually start, but the windows will be completely blank for the first 10 seconds, and after that, the 10 rows will be added.

现在,我在这方面苦苦挣扎,似乎没有很多关于 OSXAdapter 和 Jar Bundler 的文档.我究竟做错了什么?或者我不应该首先使用 OSXAdapter 或 Jar Bundler?

Now, I've struggled with this quite a bit, and it seems like there isn't a lot of documentation regarding neither OSXAdapter nor Jar Bundler. What am I doing wrong? Or shouldn't I be using OSXAdapter or Jar Bundler in the first place?

推荐答案

做完之后,我并不完全相信 SwingWorker 是一个更简单(又名:更好)的解决方案 - 仍然需要额外的线程同步(在工作线程和传入文件/名称的外部"线程).无论如何(借此机会学习,即使是错误:),以下是基本思想的概念示例的粗略证明:

After doing it, I'm not fully convinced a SwingWorker is a simpler (aka: better) solution - still requires additional thread synching (between the worker thread and the "outer" thread which passes in the file/names). Anyway (taking the opportunity to learn, and be it by errors :), below is a crude proof of concept example for the basic idea:

  • 将控制器实现为 SwingWorker,它将来自外线程的输入汇集到 EDT 中
  • 通过 doWork(..) 方法使其接受输入(来自适配器,f.i.),该方法将输入排入队列以供发布
  • 实现 doInBackground 以成功发布输入

未解决的问题

  • 同步对本地列表的访问(不是并发方面的专家,但很确定需要这样做)
  • 可靠地检测外线程的结束(这里只是在输入队列为空时停止)

欢迎反馈:-)

public class GUI {
    private JFrame frame = new JFrame();
    private DefaultTableModel model = new DefaultTableModel();
    private JTable table = new JTable(model);
    private JScrollPane pane = new JScrollPane(table);

    public GUI() {
        model.addColumn("Name");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(pane);
        frame.pack();
        frame.setVisible(true);
    }

    public void addRow(String name) {
        model.addRow(new Object[] { name });
    }

    /**
     * Controller is a SwingWorker.
     */
    public static class Controller extends SwingWorker<Void, String> {
        private GUI gui;

        private List<String> pending;

        public Controller() {
            gui = new GUI();
        }

        public void doWork(String newLine) {
            if (pending == null) {
                pending = new ArrayList<String>();
                pending.add(newLine);
                execute();
            } else {
                pending.add(newLine);
            }
        }

        @Override
        protected Void doInBackground() throws Exception {
            while (pending.size() > 0) {
                publish(pending.remove(0));
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        /**
         * @inherited <p>
         */
        @Override
        protected void process(List<String> chunks) {
            for (String object : chunks) {
                gui.addRow(object);
            }
        }

    }

    /** 
     * Simulating the adapter.
     * 
     *  Obviously, the real-thingy wouldn't have a reference 
     *  to the controller, but message the doWork refectively 
     */
    public static class Adapter implements Runnable {

        Controller controller;

        public Adapter(Controller controller) {
            this.controller = controller;
        }

        @Override
        public void run() {
            for (int i=0; i<10; i++)
            {
                controller.doWork("Line "+(i+1));
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }
    public static void main(String[] args)
    {
        System.err.println("Initializing controller");
        new Adapter(new Controller()).run();
    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger.getLogger(GUI.class.getName());
}

这篇关于使用 OSXAdapter 的 JAR Bundler 导致应用程序滞后或终止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆