SwingWorker get() 冻结接口

SwingWorker get() freezing interface

我正在使用 SwingWorker 在后台完成一些长时间的 运行 数据库调用。在执行 SwingWorker 之前,我启动了一个带有标签的 jpanel 以通知用户该应用程序正在执行一些后台工作。问题是,如果我使用 SwingWorker get() 方法获取长 运行 操作的结果,我的 jpanel 会冻结并且不会显示任何内容。如果我不使用get()方法,jpanel会正常显示。

你能告诉我我做错了什么吗?我已经在这上面花了好几个小时,却不知道为什么。 SwingWorker 在所有 jpanel 创建完成后执行,我不明白为什么它会挂起。

非常感谢!

创建jpanel并启动SwingWorker的函数:

private void snapshotOldVariables() {

    JFrame loadingJFrame = new JFrame();
    LoadingJPanel loadingJPanel = new LoadingJPanel();

    Dimension d1 = new Dimension();
    d1.setSize(500, 500);
    loadingJFrame.setResizable(false);
    loadingJFrame.setMinimumSize(d1);
    loadingJFrame.setTitle("Loading...");
    loadingJFrame.setLocationRelativeTo(null);
    loadingJFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    loadingJFrame.add(loadingJPanel);
    loadingJFrame.setVisible(true);

    loadingJPanel.updateStatus("Creating snapshot of values...");

    MySwingWorker worker = new MySwingWorker(tableRows, selectedItems);
    worker.execute();

    GMSnapshotVO snap = null;
    try {
        snap = worker.get();
    } catch (InterruptedException | ExecutionException e) {
        System.out.println(e);
    }

    loadingJPanel.updateStatus("Complete");
    loadingJFrame.dispose();


    productIds = snap.getProductIds();
    oldLocationIds = snap.getOldLocationIds();
    oldStatusIds = snap.getOldStatusIds();

}

函数等待 worker.get(): 时 jpanel 冻结的屏幕截图

带有注释 worker.get() 代码块的函数: private void snapshotOldVariables() {

    JFrame loadingJFrame = new JFrame();
    LoadingJPanel loadingJPanel = new LoadingJPanel();

    Dimension d1 = new Dimension();
    d1.setSize(500, 500);
    loadingJFrame.setResizable(false);
    loadingJFrame.setMinimumSize(d1);
    loadingJFrame.setTitle("Loading...");
    loadingJFrame.setLocationRelativeTo(null);
    loadingJFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    loadingJFrame.add(loadingJPanel);
    loadingJFrame.setVisible(true);

    loadingJPanel.updateStatus("Creating snapshot of values...");

    MySwingWorker worker = new MySwingWorker(tableRows, selectedItems);
    worker.execute();

    /* COMMENT STARTS HERE
    GMSnapshotVO snap = null;
    try {
        snap = worker.get();
    } catch (InterruptedException | ExecutionException e) {
        System.out.println(e);
    }

    loadingJPanel.updateStatus("Complete");
    loadingJFrame.dispose();

    productIds = snap.getProductIds();
    oldLocationIds = snap.getOldLocationIds();
    oldStatusIds = snap.getOldStatusIds();
    COMMENT ENDS HERE */

}

jpanel 的屏幕截图未冻结且显示正确:

据我所知,您不应该直接从 UI 线程调用 SwingWorkerget() 方法,除非您确定它已完成处理。相反,您应该在 overriden MySwingWorker.done() 中调用它,您可以在其中确定后台任务已完成执行。

这无关紧要,所有 JPanel 创建都是在阻塞之前完成的,因为 Swing 仍然需要其主 UI 线程来重新绘制和更新 UI 并保持响应。通过调用 get() 您将阻止它。

从 UI 线程你应该只调用 execute() 并且所有结果处理(在你的情况下是 productIds = snap.getProductIds(); oldLocationIds = snap.getOldLocationIds(); oldStatusIds = snap.getOldStatusIds();)应该在 done() 回调中完成。

this answer 中提供了一个简单示例。

在你的情况下应该是这样的:

//inside MySwingWorker
@Override
protected void done() {
    try {
        System.out.println("My long running database process is done. Now I can update UI without blocking/freezing it.");
        GMSnapshotVO snap = get();
        loadingJPanel.updateStatus("Complete");
        loadingJFrame.dispose();
        productIds = snap.getProductIds();
        oldLocationIds = snap.getOldLocationIds();
        oldStatusIds = snap.getOldStatusIds();
        //..do other stuff with ids
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
}

希望对您有所帮助。