java - 在 Swing 中使用 ProgressMonitorInputStream 监视压缩文件解压缩时 UI 未更新

标签 java swing

我正在开发依赖于嵌入式 H2 数据库的 swing 应用程序。因为我不想将数据库与应用程序捆绑在一起(数据库经常更新,并且我希望应用程序的新用户从最近的副本开始),所以我实现了一个解决方案,该解决方案下载数据库的压缩副本第一次启动应用程序并提取它。由于提取过程可能很慢,我添加了 ProgressMonitorInputStream显示提取过程的进度 - 不幸的是,当提取开始时,会显示进度对话框,但根本没有更新。事件似乎正在传递到事件调度线程。方法如下:

public static String extractDbFromArchive(String pathToArchive) {
    if (SwingUtilities.isEventDispatchThread()) {
        System.out.println("Invoking on event dispatch thread");
    }

    // Get the current path, where the database will be extracted
    String currentPath = System.getProperty("user.home") + File.separator + ".spellbook" + File.separator;
    LOGGER.info("Current path: " + currentPath);

    try {
        //Open the archive
        FileInputStream archiveFileStream = new FileInputStream(pathToArchive);
        // Read two bytes from the stream before it used by CBZip2InputStream

        for (int i = 0; i < 2; i++) {
            archiveFileStream.read();
        }

        // Open the gzip file and open the output file
        CBZip2InputStream bz2 = new CBZip2InputStream(new ProgressMonitorInputStream(
                              null,
                              "Decompressing " + pathToArchive,
                              archiveFileStream));
        FileOutputStream out = new FileOutputStream(ARCHIVED_DB_NAME);

        LOGGER.info("Decompressing the tar file...");
        // Transfer bytes from the compressed file to the output file
        byte[] buffer = new byte[1024];
        int len;
        while ((len = bz2.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }

        // Close the file and stream
        bz2.close();
        out.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException ex) {
        ex.printStackTrace();
    }

    try {
        TarInputStream tarInputStream = null;
        TarEntry tarEntry;
        tarInputStream = new TarInputStream(new ProgressMonitorInputStream(
                              null,
                              "Extracting " + ARCHIVED_DB_NAME,
                              new FileInputStream(ARCHIVED_DB_NAME)));

        tarEntry = tarInputStream.getNextEntry();

        byte[] buf1 = new byte[1024];

        LOGGER.info("Extracting tar file");

        while (tarEntry != null) {
            //For each entry to be extracted
            String entryName = currentPath + tarEntry.getName();
            entryName = entryName.replace('/', File.separatorChar);
            entryName = entryName.replace('\\', File.separatorChar);

            LOGGER.info("Extracting entry: " + entryName);
            FileOutputStream fileOutputStream;
            File newFile = new File(entryName);
            if (tarEntry.isDirectory()) {
                if (!newFile.mkdirs()) {
                    break;
                }
                tarEntry = tarInputStream.getNextEntry();
                continue;
            }

            fileOutputStream = new FileOutputStream(entryName);
            int n;
            while ((n = tarInputStream.read(buf1, 0, 1024)) > -1) {
                fileOutputStream.write(buf1, 0, n);
            }

            fileOutputStream.close();
            tarEntry = tarInputStream.getNextEntry();

        }
        tarInputStream.close();
    } catch (Exception e) {
    }

    currentPath += "db" + File.separator + DB_FILE_NAME;

    if (!currentPath.isEmpty()) {
        LOGGER.info("DB placed in : " + currentPath);
    }

    return currentPath;
}

此方法在事件分派(dispatch)线程上调用(SwingUtilities.isEventDispatchThread() 返回 true),因此应更新 UI 组件。我还没有将其实现为 SwingWorker,因为无论如何我都需要等待提取,然后才能继续程序的初始化。在应用程序的主 JFrame 可见之前调用此方法。我不会基于 SwingWorker + 属性更改监听器的解决方案 - 我认为 ProgressMonitorInputStream 正是我所需要的,但我想我没有做正确的事情。我使用的是 Sun JDK 1.6.18。任何帮助将不胜感激。

最佳答案

当您在 EDT 上运行提取过程时,它将阻止对 GUI 的所有更新,甚至是进度监视器。这正是 SwingWorker 将提供帮助的情况。

实际上,您通过占用 EDT 来进行数据库提取来阻止绘制。任何 GUI 更新请求(例如对 repaint() 的调用)都将排队,但实际上重新绘制这些更新永远不会运行,因为 EDT 已经很忙。

它可能起作用的唯一方法是将处理卸载到另一个线程。 SwingWorker 让这件事变得更容易。

关于java - 在 Swing 中使用 ProgressMonitorInputStream 监视压缩文件解压缩时 UI 未更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2817235/

相关文章:

java - 所有层均无模式

java - 使 Control 单击的行为类似于在 JList 上单击鼠标右键

java - 如何在 Swing 中获取 JFrame

java - 为什么我的图标在 JFrame 中没有改变?

java - 计算文件中的字符出现次数

java - 泛型类中泛型类型的访问方法

java - Spring Controller 的 Aop 注释不起作用

java - 关于java中split()的使用问题

java - 当 JTable 中的表失去焦点时,如何取消选择行?

java jtable 用新值替换旧值