侦听器的代码执行顺序
Code execution order for listeners
我已将我的问题缩小到这个简单的代码片段:
this.addClickListener(new ClickListener(){
@Override
public void buttonClick(ClickEvent event) {
Label spinner = new Label();
spinner.addStyleName("spinner");
((HorizontalLayout) event.getButton().getParent()).replaceComponent(event.getButton(), spinner);
}
});
它所做的是创建一个加载指示器并相应地用它替换点击的按钮:
- 点击 =)
好的,让我们(再次,当然是简化)通过添加行 getSaveListener().saveClick();
来执行另一个侦听器。总体而言,代码如下所示:
this.addClickListener(new ClickListener(){
@Override
public void buttonClick(ClickEvent event) {
Label spinner = new Label();
spinner.addStyleName("spinner");
((HorizontalLayout) event.getButton().getParent()).replaceComponent(event.getButton(), spinner);
getSaveListener().saveClick();
}
});
"SaveListener" 设置如下:
bu.addSaveClickListener(new SaveClickListener() {
@Override
public void saveClick() {
System.out.println("Yes1");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Yes2");
}
});
期望的行为是按钮变为微调器,写入 "Yes1",等待 4 秒,最后写入 "Yes2"。
- 点击 =)
- "Yes1"
- "Waiting"
- "Yes2"
问题是它在 旋转器的东西之前 做了 "saveClick" 的东西:
- 点击 =)
- "Yes1"
- "Waiting"
- "Yes2"
为什么"SaveListener"(.saveClick()
)先于"ClickListener"(.buttonClick()
)执行?我该如何纠正这个问题?
附加测试:
@Override
public void buttonClick(ClickEvent event) {
Label spinner = new Label();
spinner.addStyleName("spinner");
System.out.println("SPINNER!");
((HorizontalLayout) event.getButton().getParent()).replaceComponent(event.getButton(), spinner);
System.out.println("Yes?");
getSaveListener().saveClick();
}
结果为:
- 点击 =)
- "SPINNER!"
- "Yes?"
- "Yes1"
- "Waiting"
- "Yes2"
替换组件
.replaceComponent()
看起来像这样:
public void replaceComponent(Component oldComponent, Component newComponent) {
// Gets the locations
int oldLocation = -1;
int newLocation = -1;
int location = 0;
for (final Iterator<Component> i = components.iterator(); i.hasNext();) {
final Component component = i.next();
if (component == oldComponent) {
oldLocation = location;
}
if (component == newComponent) {
newLocation = location;
}
location++;
}
if (oldLocation == -1) {
addComponent(newComponent);
} else if (newLocation == -1) {
Alignment alignment = getComponentAlignment(oldComponent);
float expandRatio = getExpandRatio(oldComponent);
removeComponent(oldComponent);
addComponent(newComponent, oldLocation);
applyLayoutSettings(newComponent, alignment, expandRatio);
} else {
// Both old and new are in the layout
if (oldLocation > newLocation) {
components.remove(oldComponent);
components.add(newLocation, oldComponent);
components.remove(newComponent);
components.add(oldLocation, newComponent);
} else {
components.remove(newComponent);
components.add(oldLocation, newComponent);
components.remove(oldComponent);
components.add(newLocation, oldComponent);
}
markAsDirty();
}
}
来自API:
replaceComponent
- public void replaceComponent(Component oldComponent,
Component newComponent)
Replaces the component in the container with another one without changing position.
This method replaces component with another one is such way that the new component overtakes the position of the old component. If the
old component is not in the container, the new component is added to
the container. If the both component are already in the container,
their positions are swapped. Component attach and detach events should
be taken care as with add and remove.
Specified by:
replaceComponent in interface ComponentContainer
Parameters:
- oldComponent: the old component that will be replaced.
- newComponent: the new component to be replaced.
正如 cfrick 指出的那样,客户端 UI 将在侦听器执行完成后更新,这是正常的 Vaadin 行为。在您的示例中,侦听器执行一个长 运行ning 操作(睡眠)。完成后,UI 将更新,以便显示最后一个状态。
Vaadin 文档涵盖了以下主题:https://vaadin.com/docs/-/part/framework/components/components-progressbar.html
包含一个很好的例子。这个想法是 运行 在一个单独的线程中进行操作,并通过轮询或 Vaadin 推送更新 UI。
P.S.: 因为这个问题已经被 cfrick 作为评论回答了,我将把它作为社区 wiki 提供。
我已将我的问题缩小到这个简单的代码片段:
this.addClickListener(new ClickListener(){
@Override
public void buttonClick(ClickEvent event) {
Label spinner = new Label();
spinner.addStyleName("spinner");
((HorizontalLayout) event.getButton().getParent()).replaceComponent(event.getButton(), spinner);
}
});
它所做的是创建一个加载指示器并相应地用它替换点击的按钮:
- 点击 =)
好的,让我们(再次,当然是简化)通过添加行 getSaveListener().saveClick();
来执行另一个侦听器。总体而言,代码如下所示:
this.addClickListener(new ClickListener(){
@Override
public void buttonClick(ClickEvent event) {
Label spinner = new Label();
spinner.addStyleName("spinner");
((HorizontalLayout) event.getButton().getParent()).replaceComponent(event.getButton(), spinner);
getSaveListener().saveClick();
}
});
"SaveListener" 设置如下:
bu.addSaveClickListener(new SaveClickListener() {
@Override
public void saveClick() {
System.out.println("Yes1");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Yes2");
}
});
期望的行为是按钮变为微调器,写入 "Yes1",等待 4 秒,最后写入 "Yes2"。
- 点击 =)
- "Yes1"
- "Waiting"
- "Yes2"
问题是它在 旋转器的东西之前 做了 "saveClick" 的东西:
- 点击 =)
- "Yes1"
- "Waiting"
- "Yes2"
为什么"SaveListener"(.saveClick()
)先于"ClickListener"(.buttonClick()
)执行?我该如何纠正这个问题?
附加测试:
@Override
public void buttonClick(ClickEvent event) {
Label spinner = new Label();
spinner.addStyleName("spinner");
System.out.println("SPINNER!");
((HorizontalLayout) event.getButton().getParent()).replaceComponent(event.getButton(), spinner);
System.out.println("Yes?");
getSaveListener().saveClick();
}
结果为:
- 点击 =)
- "SPINNER!"
- "Yes?"
- "Yes1"
- "Waiting"
- "Yes2"
替换组件
.replaceComponent()
看起来像这样:
public void replaceComponent(Component oldComponent, Component newComponent) {
// Gets the locations
int oldLocation = -1;
int newLocation = -1;
int location = 0;
for (final Iterator<Component> i = components.iterator(); i.hasNext();) {
final Component component = i.next();
if (component == oldComponent) {
oldLocation = location;
}
if (component == newComponent) {
newLocation = location;
}
location++;
}
if (oldLocation == -1) {
addComponent(newComponent);
} else if (newLocation == -1) {
Alignment alignment = getComponentAlignment(oldComponent);
float expandRatio = getExpandRatio(oldComponent);
removeComponent(oldComponent);
addComponent(newComponent, oldLocation);
applyLayoutSettings(newComponent, alignment, expandRatio);
} else {
// Both old and new are in the layout
if (oldLocation > newLocation) {
components.remove(oldComponent);
components.add(newLocation, oldComponent);
components.remove(newComponent);
components.add(oldLocation, newComponent);
} else {
components.remove(newComponent);
components.add(oldLocation, newComponent);
components.remove(oldComponent);
components.add(newLocation, oldComponent);
}
markAsDirty();
}
}
来自API:
replaceComponent
- public void replaceComponent(Component oldComponent, Component newComponent)
Replaces the component in the container with another one without changing position.
This method replaces component with another one is such way that the new component overtakes the position of the old component. If the old component is not in the container, the new component is added to the container. If the both component are already in the container, their positions are swapped. Component attach and detach events should be taken care as with add and remove.
Specified by:
replaceComponent in interface ComponentContainer
Parameters:
- oldComponent: the old component that will be replaced.
- newComponent: the new component to be replaced.
正如 cfrick 指出的那样,客户端 UI 将在侦听器执行完成后更新,这是正常的 Vaadin 行为。在您的示例中,侦听器执行一个长 运行ning 操作(睡眠)。完成后,UI 将更新,以便显示最后一个状态。
Vaadin 文档涵盖了以下主题:https://vaadin.com/docs/-/part/framework/components/components-progressbar.html
包含一个很好的例子。这个想法是 运行 在一个单独的线程中进行操作,并通过轮询或 Vaadin 推送更新 UI。
P.S.: 因为这个问题已经被 cfrick 作为评论回答了,我将把它作为社区 wiki 提供。