I have a Vaadin 7 application that has a common layout and in which there is a button, that starts a thread, that does some computing.
There is a component that receives information from the computation and displays progress information etc.
Now, when I start the application and execute the computation thread, everything is fine and the view is build correctly.
When its done and I rerun it, by simply pressing the start button again, I do get
Exception in thread "Thread-56" java.lang.IllegalStateException: A connector should not be marked as dirty while a response is being written.
at com.vaadin.ui.ConnectorTracker.markDirty(ConnectorTracker.java:505)
at com.vaadin.server.AbstractClientConnector.markAsDirty(AbstractClientConnector.java:141)
at com.vaadin.ui.AbstractComponentContainer.removeComponent(AbstractComponentContainer.java:227)
at com.vaadin.ui.AbstractOrderedLayout.removeComponent(AbstractOrderedLayout.java:178)
at com.test.pipeline.view.ResultPanel.rebuildResultLayout(ResultPanel.java:46)
at com.test.pipeline.view.ResultUIProcessListener.startTests(ResultUIProcessListener.java:40)
at com.test.pipeline.RanorexClient$RanorexWorker$$Lambda$224/988244250.accept(Unknown Source)
at java.util.ArrayList.forEach(ArrayList.java:1249)
at com.test.pipeline.RanorexClient$RanorexWorker.inform(RanorexClient.java:99)
at com.test.pipeline.RanorexClient$RanorexWorker.run(RanorexClient.java:64)
The RanorexoClient$RanorexWorker
is a Thread
doing the computation.
There are listeners registered to the worker to get informed.
So I have a chain form a Thread to change UI.
The rebuildResultLayout
looks like this
void rebuildResultLayout() {
mainLayout.removeComponent(resultLayout);
resultLayout = new VerticalLayout();
mainLayout.addComponent(resultLayout);
}
so remove a layout, creating it new and adding it again. This is to get rid of information from previous run - I also tried simply to resultLayout.removeAllComponents()
, but this results in the same error.
I read somewhere to synchronise the call to the UI, so currently my inform
method looks like this
private void inform(Consumer<TestProcessListener> action) {
synchronized (UI.getCurrent()) {
processListeners.forEach(action);
}
}
What is wrong ? What must be done to avoid the exception ?
As described in https://vaadin.com/docs/-/part/framework/advanced/advanced-push.html it is required to wrap the ui modification inside a ui.access()
call.
See also @André Schild comment that it must be ensured that a valid UI reference exists