임베디드 H2 데이터베이스를 사용하는 스윙 응용 프로그램에서 작업하고 있습니다. 데이터베이스를 앱과 번들로 묶고 싶지 않기 때문에 (db가 자주 업데이트되고 새로운 복사본으로 시작하기를 원합니다.) db의 압축 된 복사본을 다운로드하는 솔루션을 구현했습니다. 응용 프로그램이 처음 시작되고 추출됩니다. 추출 프로세스가 느릴 수 있으므로 추출 프로세스의 진행 상황을 표시하기 위해 ProgressMonitorInputStream을 추가했습니다. 불행히도 추출이 시작되면 진행 대화 상자가 나타나지만 전혀 업데이트되지 않습니다. 이벤트가 이벤트 발송 스레드로 전달되는 것처럼 보입니다. 이 방법은 이벤트 처리 쓰레드 (SwingUtilities.isEventDispatchThread()가 true를 돌려 준다) 때문에 UI 구성 요소를 업데이트해야합니다에 호출됩니다Swing에서 ProgressMonitorInputStream을 사용하는 동안 UI가 업데이트되지 않아 압축 파일 압축을 모니터하지 않습니다.
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;
}
: 여기에 방법이다. 프로그램의 초기화를 진행하기 전에 추출을 기다릴 필요가 있기 때문에 이것을 SwingWorker로 구현하지 않았습니다. 이 메소드는 응용 프로그램의 기본 JFrame이 표시되기 전에 호출됩니다. 나는 SwingWorker + 속성을 기반으로 한 솔루션을 리스너가 변경하지는 않을 것입니다. ProgressMonitorInputStream이 정확히 필요한 부분이라고 생각합니다.하지만 뭔가 올바르게하고있는 것은 아닙니다. Sun JDK 1.6.18을 사용하고 있습니다. 어떤 도움이라도 대단히 감사하겠습니다.
여기서 내가 말하는 것을 생각해 보았습니다.하지만 스윙 엔지니어는 입력 스트림이 일반적으로 루프에서 읽혀지는 것을 염두에 두었을 것이라고 생각합니다. 루프가 정말 EDT를 완전히 호깅하면이 ProgressMonitorInputStream이 항상 쓸모 없다는 것을 의미합니다. –
나는 당신이 말하는 것을 이해합니다. EDT가 아닌 다른 스레드에서이 객체를 사용하면 Swing의 규칙을 위반하는 기본 'JProgressBar'에서'setValue' (다른 것들 중에서도)를 호출 할 것이기 때문에 유스 케이스를 실제로 볼 수 없습니다. 그러나 EDT를 차단하면 GUI가 업데이트되지 않는다는 사실은 변하지 않습니다. EDT에서 I/O를해서는 안됩니다. 또한 PMIS에서 봤던 모든 예는 스트림에서 실제 읽기를 수행하기 위해 주 스레드 또는 스윙 작업자를 사용하고 있습니다. – Ash
내 문제는 내 init 시퀀스로 다시 시작하기 전에 SwingWorker 스레드가 완료 될 때까지 기다려야한다는 것입니다. EDT에서 조인을 요청하면 상황이 나 빠질 것입니다. 모니터를 사용할 때 대부분 사용자가 누르는 버튼이 있습니다. 이것은 UI 요소 몇 개를 사용할 수 없도록하는 작업자 스레드를 시작하므로 사용자는 스레드가 끝날 때까지 기다릴 수 있습니다. 그러나이 추출은 UI 요소가 표시되지 않는 시점에서 발생하므로 이처럼 재생할 수 없으며 불필요한 대화 상자를 도입하지 않아 상황을 완화 할 수 없습니다. –