[英]UI not updated while using ProgressMonitorInputStream in Swing to monitor compressed file decompression
我正在開發依賴於嵌入式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;
}
在事件分發線程上調用此方法(SwingUtilities.isEventDispatchThread()返回true),因此應更新UI組件。 我尚未將其實現為SwingWorker,因為無論如何我都需要等待提取,然后才能繼續進行程序的初始化。 在應用程序的主JFrame可見之前,將調用此方法。 我不會基於SwingWorker +屬性已更改的偵聽器的解決方案-我認為ProgressMonitorInputStream正是我所需要的,但我想我做的事情不正確。 我正在使用Sun JDK 1.6.18。 任何幫助將不勝感激。
在EDT上運行提取過程時,它將阻止對GUI的所有更新,甚至進度監視器也是如此。 這正是SwingWorker
將提供幫助的情況。
實際上,您是通過拖延EDT來提取數據庫來阻止繪畫。 任何GUI更新請求(例如對repaint()
調用)都將排隊,但是實際上重繪這些更新永遠不會運行,因為EDT已經很忙。
它可能唯一可行的方法是將處理任務卸載到另一個線程。 SwingWorker
使其更容易做到這一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.