How to get access UI thread from child thread in Vaadin 8

Hi all, I am trained on [java]
(https://mindmajix.com/introduction-to-react-js), I used Vaadin 7 before. Where I could access UI thread from my child thread by using following code

UI.getCurrent().access(() → {
status.setVisible(true);
});

But currently, I am migrating from Vaddin 7 to Vaadin 8. In Vaadin 8 UI.getCurrent() returns null form the child thread. So how can we get access to UI thread from child thread?

Thank You.

This is a good and frequently asked question.

In Vaadin 8 we have introduced a fixed UI.getCurrent() so that it always returns null when called from child thread. This is because in Vaadin 7 it was already problematic. If you used thread pooling, executor service etc. UI.getCurrent() eventually returned wrong UI. This lead to many common errors. This has now been eliminated.

The correct way is not to use UI.getCurrent() from child thread at all.

Instead you should use the following pattern (pseudocode of the idea)

public class MyView extends VerticalLayout implements View {

   private UI ui;
   
   public void onAttach() {
      ui = getUI();
   }
   
   ...
   
   public void updateMe(...) {
      try {
         ui.access(() -> {
            ...  // Do the updating of the view here
         }); 
	  } catch (UIDetachedException e) {
	     ... // Do something here if you want to e.g. log that browser was closed or just swallow
	  }
   }
   
}

So idea is that access() is called in the View, not in background thread process. View knows the UI when its being attached and we used that. So from background thread you call view.updateMe(…) or possibly via its presenter request update.

Hi @Tatu I am facing one problem currently where I have a method in presenter annoted with @Async and there I set the Ui and then I notify the data update success to the same class(means the same view I called presenter) it works well but If i navigate to other view I dont get notification which I kept in the previous view Am I missing something?

I have a method in presenter annoted with @Async and there I set the Ui

This is an anti pattern, you should not pass the UI as parameter to the thread. Instead add a method that does what you need in the view using the pattern I have in the MyView example above. That you can safely call from the thread.

umm ok I understood your point but still didnt get success…!!

Actually my code goes like

public class myWindow extends Window{

public void init(){
	current=Ui.getcurrent();
}

private void saveData(){
	UI.getCurrent().setPollInterval(1000);
        mainUI.showSpinner();//Vaadin progressbar setting visible true
         abcpresenter.saveData(param,param);
         UI.setCurrent(current);
        close();
}

public void notifyUsers(){
	UI.getCurrent().access(() -> {
           mainUI. .hideSpinner();//hide vaadin progress bar
            Notification.show("Task done"));
        });
}	

}

//here is my presenter
public class AbcPresenter(){

@Async
public void saveData(args...){
	//saving action done then notify again to myWindow class
	myWindow.notifyUsers();

}

Actually what happens is It updates the UI till I am in the same view that means I get the Notification and spinner also gets hidden thats perfect but my requirements is when I click button to save data it starts its process in background and user can navigate to any view.so from other view the Notification didn’t appear but when I click a button or something from the other view that is when request is made to server that notification appears.

Actually by this Issue I am really stuck…!! It would be great help if you can tell what modifications are needed?And I have undergone all post related to this in stack overflow and forums.

I have developed projects in Vaadin 8 and Vaadin 14 (Didnt face this type of issues)but I am back to vaadin 7 for some of requirements…!!

Thanks

Your problem is that you use UI.getCurrent() which does not work when run from background thread. Your view extends Window, which is a component, so you can use getUI() like in my example above. Do not forget try … catch, since in long running async processes it is possible that user closes the Browser before task ends.

You can find more comprehensive example in funtional application here

View: Request update users from presenter

https://github.com/TatuLund/cdi-demo/blob/master/src/main/java/org/vaadin/cdidemo/views/admin/AdminViewImpl.java#L43

Presenter: Fetch users in background thread using executor service and future, finally ask to update

https://github.com/TatuLund/cdi-demo/blob/master/src/main/java/org/vaadin/cdidemo/views/admin/AdminPresenter.java#L48

View: Update users in access

https://github.com/TatuLund/cdi-demo/blob/master/src/main/java/org/vaadin/cdidemo/views/admin/AdminViewImpl.java#L56

You are using Spring @Async, that is ok to use, it is syntactic sugaring on top of executor service.

yes I replaced UI.getCurrent with getUI() Read your example and like as you said @Async is ok so I didn’t replaced it…!!

so now the code is like

public class myWindow extends Window{

private UI ui;

@Autowired
private AbcPresenter abcpresenter;

@Override
    public void attach() {
        super.attach();
        ui = getUI();
    }

private void saveData(){
	ui.setPollInterval(1000);
        mainUI.showSpinner();//Vaadin progressbar setting visible true
         abcpresenter.saveData(param,param);
         UI.setCurrent(ui);
        close();
}

public void notifyUsers(){
try{
ui.access(() -> {
           mainUI. .hideSpinner();//hide vaadin progress bar
            Notification.show("Task done"));
        });
}catch(Exception e){
	e.printStackTrace();
}
	
}	

}

//here is my presenter
public class AbcPresenter(){

@Async
public void saveData(args...){
	//saving action done then notify again to myWindow class
	myWindow.notifyUsers();

}

The Problem still exists like It works If I am in the current view but if I Navigate to Other view I am not able to receive notification…!!

can there be a problem with @Async?

I am worried like the threads aren’t able to communicate as it will be 2 threads according to code like something is missing that is not making request to server for UI update beacuse as soon as the process starts and if user navigates to other views(I have a side bar from which I navigate to other view from the current view (in which the process is running in background)I am not able to see notification.

I do not get the role of this one

private void saveData(){
	ui.setPollInterval(1000);
        mainUI.showSpinner();//Vaadin progressbar setting visible true
         abcpresenter.saveData(param,param);
         UI.setCurrent(ui);
        close();
}

Firstly, you should not have the need to UI.setCurrent(ui). Also why you have ui.setPollInterval(1000)? Are you using polling instead of Push. If you study the app I linked, it is using Push instead.

yes I got your point let me use push instead of poll I think it will work.!! because polling is risky by the means of this type of implementation.

thanks Tatu…!!

finally It worked…!! @Tatu Lund

Using push mechanism with transport = Transport.LONG_POLLING

I don’t know why it worked with LONG POLLING and not just with @push…!!

I don’t know why it worked with LONG POLLING and not just with @push…!!

LONG POLLING mode uses just http, while the other modes use WebSockets. So it may be that your proxy server is not configured for web sockets you have e.g. very old Tomcat (e.g. 7) version that does not fully support WebSockets.