when an UI instance is created in Vaadin Flow ?
I suggest you see for yourself. Track the UI
instances in your own code. Tracking is quite easy, as explained in the manual [here]
(https://vaadin.com/docs/v14/flow/advanced/tutorial-ui-init-listener.html) and [here]
(https://vaadin.com/docs/v14/flow/advanced/tutorial-service-init-listener.html).
Let’s walk through the steps, and see example code.
For a new Vaadin 14 project, add the following to your POM to get the necessary Node.js & npm tools added to your project. [Discussed on Stack Overflow]
(https://stackoverflow.com/q/57502852/642706).
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<!-- Use the latest released version:
https://repo1.maven.org/maven2/com/github/eirslett/frontend-maven-plugin/ -->
<version>1.8.0</version>
<executions>
<execution>
<!-- optional: you don't really need execution ids, but it looks nice in your build log. -->
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<!-- optional: default phase is "generate-resources" -->
<phase>generate-resources</phase>
</execution>
</executions>
<configuration>
<nodeVersion>v10.16.3</nodeVersion>
<!-- optional: with node version greater than 4.0.0 will use npm provided by node distribution -->
<!-- <npmVersion>2.15.9</npmVersion>-->
<!-- optional: where to download node and npm from. Defaults to https://nodejs.org/dist/ -->
<!-- <downloadRoot>http://myproxy.example.org/nodejs/</downloadRoot>-->
</configuration>
</plugin>
On whatever content you are showing, such as a MainView
class, spill to console when instantiating. Notice the System.out.println
I added to the MainView
class created by default in the Vaadin starter project.
package work.basil.example;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.PWA;
import java.time.Instant;
/**
* The main view contains a button and a click listener.
*/
@Route ( "" )
@PWA ( name = "Project Base for Vaadin", shortName = "Project Base" )
public class MainView extends VerticalLayout
{
public MainView ( )
{
System.out.println ( "BASIL - MainView constructor." + Instant.now () );
Button button = new Button ( "Click me" ,
event -> Notification.show ( "Clicked!" ) );
add ( button );
}
}
Add the listeners that are called when (a) the VaadinService
begins, and (b) a UI
object is being initialized. Both are done in this single class shown next.
Notice how we interregate the UI
object for its ID number. I expect you will see that number increase, presumably because a new UI
object was instantiated.
package work.basil.example;
import com.vaadin.flow.server.ServiceInitEvent;
import com.vaadin.flow.server.UIInitEvent;
import com.vaadin.flow.server.VaadinServiceInitListener;
import java.time.Instant;
public class ApplicationServiceInitListener
implements VaadinServiceInitListener
{
@Override
public void serviceInit ( ServiceInitEvent serviceInitEvent )
{
System.out.println( "BASIL - ServiceInitEvent." + Instant.now() );
serviceInitEvent.getSource().addUIInitListener(
( UIInitEvent uiInitEvent ) -> {
System.out.println( "BASIL - UIInitEvent. UI id # " + uiInitEvent.getUI().getUIId() + ". " + Instant.now() );
} );
}
}
To activate that class, we must hook it into the [Java Server Provider Interface (SPI)]
(https://docs.oracle.com/javase/tutorial/ext/basics/spi.html).
Inside the src
folder of your project, in the nested resources
folder, create a folder META-INF
. This is [part of the JAR format]
(https://stackoverflow.com/q/70216/642706), not to be confused with[ WEB-INF
]
(https://stackoverflow.com/questions/19786142/what-is-web-inf-used-for-in-a-java-ee-web-application). Inside that new META-INF
folder, create a new folder named services
.
Inside that services
folder, create a plain text file. It must be name exactly: com.vaadin.flow.server.VaadinServiceInitListener
. This is the fully-qualified name of the interface for which we want to supply an implementation. Inside that file, add this one line, the fully-qualified name of the listener class we created. In the case of this example here: work.basil.example.ApplicationServiceInitListener
. See attached screenshot.
If starting with a fresh project, you may want to add another view class with @Route
to see the effects of routing.
package work.basil.example;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import java.time.Instant;
@Route ( "other" )
public class OtherView extends VerticalLayout
{
public OtherView ( )
{
System.out.println( "BASIL - OtherView constructor." + Instant.now() );
H1 h1 = new H1( "Other" );
this.add( h1 );
}
}
Do a Maven clean
. Run your web app.
I believe you will see a new UI
object (a) when routing, and (b) when user clicks the browser Reload button. The new @PreserveOnRefresh
annotation has no effect on this behavior. You may see the UI init occur in other cases as well. So you cannot count on the UI
object sticking around.
Example output in Vaadin 14.0.2. The 4th & 5th lines appeared whet I clicked the browser Reload button.
BASIL - ServiceInitEvent.2019-08-28T05:59:07.882575Z
BASIL - UIInitEvent. UI id # 0. 2019-08-28T05:59:07.981299Z
BASIL - MainView constructor.2019-08-28T05:59:07.994759Z
BASIL - UIInitEvent. UI id # 1. 2019-08-28T05:59:21.101277Z
BASIL - MainView constructor.2019-08-28T05:59:21.101884Z
The 4th & 5th lines appeared when I clicked the browser Reload button.
If I add a @PreserveOnRefresh to my MainView
, and hit Reload button, I see line # 4 (UIInitEvent
), but not # 5 (MainView
constructor).
