我创建了一个弹出窗口来显示某些内容的进度,并且它与我的下载器工作正常,所有内容都在更新。
private void downloadFile(String link, String directory, String name) throws IOException {
task = new Downloader(link, directory, name);
task.start();
}
并在Downloader类中:
public void run() {
try {
while ((length = is.read(b)) != -1) {
downloaded += length;
bout.write(b, 0, length);
int percent = (int) ((downloaded * 100) / fileLength);
window.modify1("Downloading " + name + ".jar");
window.modify2((int) downloaded, "Progress: " + percent + "% [" + String.valueOf(downloaded).subSequence(0, String.valueOf(downloaded).length() - 1) + "kb/" + String.valueOf(fileLength).subSequence(0, String.valueOf(fileLength).length() - 1) + "kb]");
}
is.close();
bout.close();
window.exit();
Creator c = new Creator(directory, name);
c.create();
this.join();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
但是,当我尝试在另一个线程中执行几乎相同的操作时,它不起作用。在线程完成之前,弹出窗口中没有任何内容显示。
LauncherThread t = new LauncherThread();
t.start();
try {
t.join();
} catch (InterruptedException e2) {
e2.printStackTrace();
}
并在LauncherThread类中:
public void run() {
window.modify1("Fetching data...");
window.modify2(0, "Progress: 0% [0/10]");
Main.trust();
window.modify2(1, "Progress: 10% [1/10]");
Main.bukkitVersions = Finder.findBukkitVersions();
window.modify2(2, "Progress: 20% [2/10]");
Main.spigotVersions = Finder.findSpigotVersions();
window.modify2(3, "Progress: 30% [3/10]");
Main.vanillaVersion = Finder.findVanillaVersion();
window.modify2(4, "Progress: 40% [4/10]");
Main.bukkitLinks = new String[3];
Main.bukkitLinks[0] = Finder.findDownloadLink("bukkit", "rb");
window.modify2(5, "Progress: 50% [5/10]");
Main.bukkitLinks[1] = Finder.findDownloadLink("bukkit", "beta");
window.modify2(6, "Progress: 60% [6/10]");
Main.bukkitLinks[2] = Finder.findDownloadLink("bukkit", "dev");
window.modify2(7, "Progress: 70% [7/10]");
Main.spigotLinks = new String[2];
Main.spigotLinks[0] = Finder.findDownloadLink("spigot", "lastStable");
window.modify2(8, "Progress: 80% [8/10]");
Main.spigotLinks[1] = Finder.findDownloadLink("spigot", "lastBuild");
window.modify2(9, "Progress: 90% [9/10]");
Main.vanillaLink = Finder.findDownloadLink("vanilla", null);
window.modify2(10, "Progress: 100% [10/10]");
window.exit();
}
我还是Java新手,所以我为自己的无知而道歉。
编辑:我将t.start()方法包含在SwingUtilities.invokeLater()中,现在可以正常工作了。但新问题是主类不再等待LauncherThread完成。
答案 0 :(得分:0)
我选择了简单(可能很糟糕)的方式。初始化方法在完成后在LauncherThread中调用。
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
new Main();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Main() {
launch();
}
/**
* Run launcher.
*/
private void launch() {
LauncherThread t = new LauncherThread(this);
t.start();
}
我通过构造函数将Main实例传递给LauncherThread类,因此我可以从那里调用initialize方法,而不必使用静态访问。
main.initialize();
答案 1 :(得分:0)
您正在遇到严重问题,我担心您当前的解决方案无法解决问题但只是隐藏它。
根本问题是Swing(作为大多数可比较的库)不是线程安全的。因此,只有一个线程可以访问Swing组件。该线程不是任意的,而是一个名为EDT(Event Dispatch Thread)的特殊线程。
其后果是:
UI的初始化必须包含在对SwingUtilities.invokeLater或SwingUtilities.invokeAndWait
如果您在单独的线程中工作,则代码不得直接触及Progressbar。相反,它必须通过上述两种方法向进度条发送更新。
如果您现在没有这样做并且您的代码无法正常工作,那么这并不意味着它将在明天或在其他机器上工作,或者当天气变化或中国政府发生变化时。
如果你想要,一个线程在另一个线程上等待你应该查看像CountDownLatch之类的东西,只要确保你不要阻止EDT,因为当它被阻止时,UI中不会有任何颜色,所以应用程序似乎对用户来说已经死了。再次通过invokeLater执行一些代码可能会解决这个问题。
答案 2 :(得分:0)
当我必须从另一个线程更新Swing组件时,我将在
中执行此操作SwingUtilites.invokeLater(new Runnable() {
//set new values
});
来自Javadoc ot方法:
Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread. This will happen after all pending AWT events have been processed. This method should be used when an application thread needs to update the GUI.
还有一件事,
您可以考虑通过SwingWorker
执行您的申请,这些对象与EDT
是友好的。但请记住,它们是在有限ThreadPool
内执行的。我尝试过一次推出50多名摇摆工作者来更新面板的组件,但它只适用于前10个。可能会改变它们让它们全部运行,但我改变了我的方法。