一尘不染

Java使用OSXAdapter的JAR Bundler导致应用程序滞后或终止

java

我创建了一个简单的Java应用程序,该应用程序在连续10秒内每秒每秒向中添加新行JTable。它包括三个类。

程序启动后被调用的主类

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

And finally, the GUI

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的文件中。我已成功完成此操作,我的应用程序打开,计数到十,每秒写一次。

Now, for the problem

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

由于我需要查看双击的文件,因此我使用OSXAdapter,这是Apple为此目的制造的Java库。这是通过更改Controller类的构造函数并添加另一个方法来实现的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行。

Help

现在,我为此付出了很多努力,似乎关于OSXAdapter和Jar Bundler的文档都很少。我究竟做错了什么?还是我不应该首先使用OSXAdapter或Jar Bundler?


阅读 270

收藏
2020-03-04

共1个答案

一尘不染

完成此操作后,我不完全相信SwingWorker是一个更简单(又称更好)的解决方案-仍然需要其他线程同步(在工作线程和传入文件/名称的“外部”线程之间)。无论如何(利用学习的机会,并避免错误:),以下是基本思想的概念证明示例:

  • 将Controller实现为SwingWorker,它将来自外线程的输入汇集到EDT中
  • 通过doWork(..)方法使其接受输入(来自适配器,fi),该方法将输入排队以便发布
  • 实现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());
}
2020-03-04