vaadin 10 - 推送 - 标签不会更新
vaadin 10 - Push - Label won't update
MainView 包含 InformationCOMponent:
@Push
@Route
public class MainView extends VerticalLayout {
InformationComponent infoComponent;
public MainView(@Autowired StudentRepository studentRepo, @Autowired Job jobImportCsv, @Autowired JobLauncher jobLauncher, @Value("${file.local-tmp-file}") String inputFile) {
[...] // some stuffs
infoComponent = new InformationComponent(studentRepo);
add(infoComponent);
}
//update when job process is over
private void uploadFileSuccceed() {
infoComponent.update(myUploadComponent.getFile());
}
信息组件:
public class InformationComponent extends HorizontalLayout {
StudentRepository studentRepo;
Label nbLineInFile = new Label();
VerticalLayout componentLeft = new VerticalLayout();;
VerticalLayout componentRight = new VerticalLayout();;
public InformationComponent(StudentRepository studentRepo) {
[...] // some init and style stuff
addLine("Nombre de lignes dans le fichier", nbLineInFile);
}
private void addLine(String label, Label value) {
componentLeft.add(new Label(label));
componentRight.add(value);
}
public void update(File file) {
try {
long nbLines = Files.lines(file.toPath(), Charset.defaultCharset()).count();
System.out.println("UPDATED! " +nbLines); // value is display in console ok!
UI.getCurrent().access(() -> nbLineInFile.setText(nbLines)); // UI is not updated!!
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
当我从 MainView 调用 InformationComponent 时标签在浏览器中没有更新。
UI.getCurrent().access(() -> nbLineInFile.setText(nbLines))
也可以尝试使用 @Push(PushMode.MANUAL) 和 ui.push();但也不管用...
完整的源代码在这里:https://github.com/Tyvain/ProcessUploadedFile-Vaadin_SpringBatch/tree/push-not-working
我怀疑这里的问题是 uploadFileSuccceed()
是来自后台线程的 运行,在这种情况下 UI.getCurrent()
将 return null
。这将导致 NullPointerException
终止后台线程,或者异常被捕获并被调用者静默忽略。另一种选择是 uploadFileSuccceed()
通过不同的浏览器 window 发生,因此也是不同的 UI
实例,这意味着更改将被推送到错误的 UI
上下文中.
正是由于这些原因,UI.getCurrent().access(...)
通常是一种反模式,尽管不幸的是它在旧示例中被广泛使用。
您可以通过在 update
方法的开头记录 UI.getCurrent()
的值并将其与 UI.getCurrent()
的值进行比较来检查这是否是问题的原因例如在 InformationComponent
.
的构造函数中
要正确解决该问题,您应该将正确的 UI
实例传递到整个事件链,这些事件源自任何触发后台处理启动的事件。您还应该注意,使用任何 Component
子类中可用的 getUI()
方法可能很诱人,但该方法不是线程安全的,因此应避免在后台线程中使用。
作为最后的通知,我建议在这种情况下使用 Span
或 Text
组件而不是 Label
。在 Vaadin 10 中,Label
组件已更改为使用 <label>
HTML 元素,这意味着它主要用作输入组件的标签。
根据 Leif 提供的信息,您应该执行类似于以下示例的操作。
在运行时,当这个 HorizontalLayout
subclass object is attached to a parent UI
object, its onAttach
method is called. At that point we can remember the UI by storing its reference is a member variable named ui
. Actually, an Optional<UI>
is returned rather than a UI
对象时,我们需要测试空值,尽管它在 onAttach
点永远不应该为空值。
public class InformationComponent extends HorizontalLayout {
UI ui;
StudentRepository studentRepo;
Label nbLineInFile = new Label();
VerticalLayout componentLeft = new VerticalLayout();;
VerticalLayout componentRight = new VerticalLayout();;
public InformationComponent(StudentRepository studentRepo) {
[...] // some init and style stuff
addLine("Nombre de lignes dans le fichier", nbLineInFile);
}
private void addLine(String label, Label value) {
componentLeft.add(new Label(label));
componentRight.add(value);
}
public void update(File file) {
try {
long nbLines = Files.lines(file.toPath(), Charset.defaultCharset()).count();
System.out.println("UPDATED! " +nbLines); // value is display in console ok!
this.ui.access(() -> nbLineInFile.setText(nbLines)); // UI is not updated!!
} catch (IOException e) {
throw new RuntimeException(e);
} catch (UIDetachedException e) {
// Do here what is needed to do if UI is no longer attached, user has closed the browser
}
@Override // Called when this component (this `HorizontalLayout`) is attached to a `UI` object.
public void onAttach() {
ui = this.getUI().orElseThrow( () -> new IllegalStateException("No UI found, which should be impossible at point of `onAttach` being called.") );
}
MainView 包含 InformationCOMponent:
@Push
@Route
public class MainView extends VerticalLayout {
InformationComponent infoComponent;
public MainView(@Autowired StudentRepository studentRepo, @Autowired Job jobImportCsv, @Autowired JobLauncher jobLauncher, @Value("${file.local-tmp-file}") String inputFile) {
[...] // some stuffs
infoComponent = new InformationComponent(studentRepo);
add(infoComponent);
}
//update when job process is over
private void uploadFileSuccceed() {
infoComponent.update(myUploadComponent.getFile());
}
信息组件:
public class InformationComponent extends HorizontalLayout {
StudentRepository studentRepo;
Label nbLineInFile = new Label();
VerticalLayout componentLeft = new VerticalLayout();;
VerticalLayout componentRight = new VerticalLayout();;
public InformationComponent(StudentRepository studentRepo) {
[...] // some init and style stuff
addLine("Nombre de lignes dans le fichier", nbLineInFile);
}
private void addLine(String label, Label value) {
componentLeft.add(new Label(label));
componentRight.add(value);
}
public void update(File file) {
try {
long nbLines = Files.lines(file.toPath(), Charset.defaultCharset()).count();
System.out.println("UPDATED! " +nbLines); // value is display in console ok!
UI.getCurrent().access(() -> nbLineInFile.setText(nbLines)); // UI is not updated!!
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
当我从 MainView 调用 InformationComponent 时标签在浏览器中没有更新。
UI.getCurrent().access(() -> nbLineInFile.setText(nbLines))
也可以尝试使用 @Push(PushMode.MANUAL) 和 ui.push();但也不管用...
完整的源代码在这里:https://github.com/Tyvain/ProcessUploadedFile-Vaadin_SpringBatch/tree/push-not-working
我怀疑这里的问题是 uploadFileSuccceed()
是来自后台线程的 运行,在这种情况下 UI.getCurrent()
将 return null
。这将导致 NullPointerException
终止后台线程,或者异常被捕获并被调用者静默忽略。另一种选择是 uploadFileSuccceed()
通过不同的浏览器 window 发生,因此也是不同的 UI
实例,这意味着更改将被推送到错误的 UI
上下文中.
正是由于这些原因,UI.getCurrent().access(...)
通常是一种反模式,尽管不幸的是它在旧示例中被广泛使用。
您可以通过在 update
方法的开头记录 UI.getCurrent()
的值并将其与 UI.getCurrent()
的值进行比较来检查这是否是问题的原因例如在 InformationComponent
.
要正确解决该问题,您应该将正确的 UI
实例传递到整个事件链,这些事件源自任何触发后台处理启动的事件。您还应该注意,使用任何 Component
子类中可用的 getUI()
方法可能很诱人,但该方法不是线程安全的,因此应避免在后台线程中使用。
作为最后的通知,我建议在这种情况下使用 Span
或 Text
组件而不是 Label
。在 Vaadin 10 中,Label
组件已更改为使用 <label>
HTML 元素,这意味着它主要用作输入组件的标签。
根据 Leif 提供的信息,您应该执行类似于以下示例的操作。
在运行时,当这个 HorizontalLayout
subclass object is attached to a parent UI
object, its onAttach
method is called. At that point we can remember the UI by storing its reference is a member variable named ui
. Actually, an Optional<UI>
is returned rather than a UI
对象时,我们需要测试空值,尽管它在 onAttach
点永远不应该为空值。
public class InformationComponent extends HorizontalLayout {
UI ui;
StudentRepository studentRepo;
Label nbLineInFile = new Label();
VerticalLayout componentLeft = new VerticalLayout();;
VerticalLayout componentRight = new VerticalLayout();;
public InformationComponent(StudentRepository studentRepo) {
[...] // some init and style stuff
addLine("Nombre de lignes dans le fichier", nbLineInFile);
}
private void addLine(String label, Label value) {
componentLeft.add(new Label(label));
componentRight.add(value);
}
public void update(File file) {
try {
long nbLines = Files.lines(file.toPath(), Charset.defaultCharset()).count();
System.out.println("UPDATED! " +nbLines); // value is display in console ok!
this.ui.access(() -> nbLineInFile.setText(nbLines)); // UI is not updated!!
} catch (IOException e) {
throw new RuntimeException(e);
} catch (UIDetachedException e) {
// Do here what is needed to do if UI is no longer attached, user has closed the browser
}
@Override // Called when this component (this `HorizontalLayout`) is attached to a `UI` object.
public void onAttach() {
ui = this.getUI().orElseThrow( () -> new IllegalStateException("No UI found, which should be impossible at point of `onAttach` being called.") );
}