Maduka Deshan Rodrigo
Maduka Deshan Rodrigo

Reputation: 19

How to navigate to another vaadin class UI using thread

I created an asynchronous thread to navigate from one UI class to another UI class after 30 seconds by showing a timer(H1 tag) to the user. Thread successfully shows updates on H1 tag but does not navigate to the next UI class after the end of 30 seconds. I'm getting an error Exception call "java.lang.IllegalStateException: Cannot access state in VaadinSession or UI without locking the session." for ui.navigate(ScoreBoard.class); call.

@Override
protected void onAttach(AttachEvent attachEvent) {
    // Start the data feed thread
    thread = new FeederThread(attachEvent.getUI(),timerc);
    thread.start();
}

//Thread
private static class FeederThread extends Thread {
    private final com.vaadin.flow.component.UI ui;
    private  final  H1 element;

    private int count = 30;


    public FeederThread(com.vaadin.flow.component.UI ui,H1 element) {
        this.ui = ui;
        this.element = element;
    }

    @Override
    public void run() {
        while (count>-1){
            try {
                Thread.sleep(1000);
                ui.access(()-> {
                    element.setText(String.valueOf(count)+" sec");
                });
                count--;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        }
        //Exception in thread "Thread-46" java.lang.IllegalStateException: //Cannot access state in VaadinSession or UI without locking the session.
        ui.navigate(ScoreBoard.class);
    }
}

//Exception in thread "Thread-46" java.lang.IllegalStateException: //Cannot access state in VaadinSession or UI without locking the session. ui.navigate(ScoreBoard.class);

Upvotes: 0

Views: 583

Answers (2)

Alejandro Duarte
Alejandro Duarte

Reputation: 1479

You need to enable push by using @Push in your class. Also, since the navigation action is part of the UI state, you need to use UI.access. Finally, you don't need to call getCurrent() if you already have the instance. So this is what you need in short:

...
@Push
public class MainView extends VerticalLayout {

    ...
        ui.access(() -> ui.navigate(ScoreBoard.class));
    ...
}

Upvotes: 0

Tatu Lund
Tatu Lund

Reputation: 10643

UI.getCurrent() is returning null when called in Thread, this is intentional. This way it can be ensured that no wrong UI is returned.

The correct pattern would be for example add a method in your view, which updates the Text. In the method you can use getUi().ifPresent(ui -> ui.access(..)) . Then you can call that method from the Thread safely. Same can be applied with navigation.

Alternatively you can pass ui as parameter to your Thread as you have done. When you do so, getCurrent() call is obsolote.

Upvotes: 1

Related Questions