模态对话后 SwingWorker publish() 和 process(List) 乱序
SwingWorker publish() and process(List) out of order after Modal dialogue
在复杂的 Java 应用程序中,我扩展了 SwingWorker,因此我可以在后台处理从套接字读取数据。套接字提供了更新 GUI 所需的大量数据。
有一个特殊的警告 - 写入套接字的服务器以客户端所依赖的非常特定的顺序写入内容。将其视为发送术语的定义,然后发送术语的使用。如果应用程序没有首先获取定义,它会崩溃或显示错误数据。这不是问题,因为服务器很小心地做对了,而且套接字是 TCP,所以我得到了按顺序交付。很简单:我从 Worker.doInBackground 函数中的套接字读取数据,解析它并调用 publish()。在 Worker.process(List) 中,我按顺序遍历列表,处理套接字给我的东西。一切顺利。
一切都很好,除非服务器发送的内容说服客户端弹出模态对话框,这可能会在它发送的内容的早期发生。当model box up时,后台线程继续读取socket并调用publish(),这是意料之中的。但是 worket.process(List) (请注意,这是放置在模态对话框中的代码)开始被调用,其中的内容乱七八糟。它可能仍在处理最后一个传递给它的列表,并被处理模态框正在执行的任何事件递归调用。
我的笔记说在 process(List) 中做 GUI 的东西是可以的,而且只能在 process(List) 中。我认为在 doInBackground() 中执行 GUI 操作是不安全的。所以弹出一个对话框,我假设,需要在进程(列表)中发生。
有没有办法告诉对话框停止调用 doInBackground() 或 process()?在关闭该对话框之前,我不想或不需要 运行 任何内容。有没有更聪明的方法来完成我需要做的事情?服务器随时可以免费发送新内容,顺序总是很重要,所以我看不出什么时候可以安全地设置对话框。
我尝试同步,在对话框打开时持有锁,并在调用 publish() 之前让 doInBackground 在锁对象上等待。没有骰子 - 它们可能是同一线程的 运行,并且 java 锁是递归的。 (如果他们不这样做,对话框可能会挂起。)
我能想到一个可能笨拙的解决方法。我可以用序列号标记事物到达 doInbackground() 的顺序,并且在处理过程中)我可以重新发布我得到的任何序列号意外太高的东西。但是我可能会陷入一个紧密的循环,直到对话框被关闭 ("Item 1129 is too high. Republish. Item 1129 is too high. Republish...")
正确的方法是什么?
我不确定我是否 100% 理解您的问题(如果我的回答是 "offtopic",请告诉我),但我会强调这一部分:
Is there a way to tell the dialog box to stop calling
doInBackground(), or process()? I don't want or need anything to run
until that dialog box is dismissed.
使用锁变量是实现这一点的方法。看我的例子。 代码内的注释。
public class Worker extends SwingWorker<Void, String> {
private JDialog dialog;
public Worker() {
dialog = new JDialog();
dialog.setModal(true);
dialog.setLocationByPlatform(true);
//Plays no role but since there is no frame (icon in task bar)
//you might not be able to terminate the program
dialog.setAlwaysOnTop(true);
}
@Override
protected Void doInBackground() throws Exception {
int times = 0;
while (true) { //Worker runs forever
//If dialog is visible, just wait it until it is closed
if (dialog.isVisible()) { //or dialog.isDisplayable()
Thread.sleep(10); //Rest cpu
continue;
}
//Here you read the data from server and you publish things to GUI - "process" method
if (times == 5)
publish("dialog");
else if (times == 10)
publish("exit");
else
publish("chunk");
times++;
Thread.sleep(500);
}
}
@Override
protected void process(List<String> chunks) {
String chunk = chunks.get(0);
System.out.println("Processing....:" + chunk);
//A dialog requested
if ("dialog".equals(chunk)) {
dialog.setVisible(true);
System.out.println("Dialog closed");
}
//Exit requested
else if ("exit".equals(chunk)) {
System.out.println("Ran process 10 times, exiting....");
System.exit(1);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Worker().execute());
}
}
在复杂的 Java 应用程序中,我扩展了 SwingWorker,因此我可以在后台处理从套接字读取数据。套接字提供了更新 GUI 所需的大量数据。
有一个特殊的警告 - 写入套接字的服务器以客户端所依赖的非常特定的顺序写入内容。将其视为发送术语的定义,然后发送术语的使用。如果应用程序没有首先获取定义,它会崩溃或显示错误数据。这不是问题,因为服务器很小心地做对了,而且套接字是 TCP,所以我得到了按顺序交付。很简单:我从 Worker.doInBackground 函数中的套接字读取数据,解析它并调用 publish()。在 Worker.process(List) 中,我按顺序遍历列表,处理套接字给我的东西。一切顺利。
一切都很好,除非服务器发送的内容说服客户端弹出模态对话框,这可能会在它发送的内容的早期发生。当model box up时,后台线程继续读取socket并调用publish(),这是意料之中的。但是 worket.process(List) (请注意,这是放置在模态对话框中的代码)开始被调用,其中的内容乱七八糟。它可能仍在处理最后一个传递给它的列表,并被处理模态框正在执行的任何事件递归调用。
我的笔记说在 process(List) 中做 GUI 的东西是可以的,而且只能在 process(List) 中。我认为在 doInBackground() 中执行 GUI 操作是不安全的。所以弹出一个对话框,我假设,需要在进程(列表)中发生。
有没有办法告诉对话框停止调用 doInBackground() 或 process()?在关闭该对话框之前,我不想或不需要 运行 任何内容。有没有更聪明的方法来完成我需要做的事情?服务器随时可以免费发送新内容,顺序总是很重要,所以我看不出什么时候可以安全地设置对话框。
我尝试同步,在对话框打开时持有锁,并在调用 publish() 之前让 doInBackground 在锁对象上等待。没有骰子 - 它们可能是同一线程的 运行,并且 java 锁是递归的。 (如果他们不这样做,对话框可能会挂起。)
我能想到一个可能笨拙的解决方法。我可以用序列号标记事物到达 doInbackground() 的顺序,并且在处理过程中)我可以重新发布我得到的任何序列号意外太高的东西。但是我可能会陷入一个紧密的循环,直到对话框被关闭 ("Item 1129 is too high. Republish. Item 1129 is too high. Republish...")
正确的方法是什么?
我不确定我是否 100% 理解您的问题(如果我的回答是 "offtopic",请告诉我),但我会强调这一部分:
Is there a way to tell the dialog box to stop calling doInBackground(), or process()? I don't want or need anything to run until that dialog box is dismissed.
使用锁变量是实现这一点的方法。看我的例子。 代码内的注释。
public class Worker extends SwingWorker<Void, String> {
private JDialog dialog;
public Worker() {
dialog = new JDialog();
dialog.setModal(true);
dialog.setLocationByPlatform(true);
//Plays no role but since there is no frame (icon in task bar)
//you might not be able to terminate the program
dialog.setAlwaysOnTop(true);
}
@Override
protected Void doInBackground() throws Exception {
int times = 0;
while (true) { //Worker runs forever
//If dialog is visible, just wait it until it is closed
if (dialog.isVisible()) { //or dialog.isDisplayable()
Thread.sleep(10); //Rest cpu
continue;
}
//Here you read the data from server and you publish things to GUI - "process" method
if (times == 5)
publish("dialog");
else if (times == 10)
publish("exit");
else
publish("chunk");
times++;
Thread.sleep(500);
}
}
@Override
protected void process(List<String> chunks) {
String chunk = chunks.get(0);
System.out.println("Processing....:" + chunk);
//A dialog requested
if ("dialog".equals(chunk)) {
dialog.setVisible(true);
System.out.println("Dialog closed");
}
//Exit requested
else if ("exit".equals(chunk)) {
System.out.println("Ran process 10 times, exiting....");
System.exit(1);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Worker().execute());
}
}