Loading...
Important Notice - Forums is archived

To simplify things and help our users to be more productive, we have archived the current forum and focus our efforts on helping developers on Stack Overflow. You can post new questions on Stack Overflow or join our Discord channel.

Product icon
TUTORIAL

Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.

How can I update a chart inside a thread?

Agent 100
3 years ago Jan 04, 2020 9:04pm
Kaspar Scherrer
3 years ago Jan 06, 2020 8:23am

You need to call

ui.access(() -> {
    // everything that will affect the UI is done here. for example ADC0.addData(...)
});

I'm having a hard time finding the official docs for this, but here's a reference from stackoverflow.

You need to keep in mind that the method UI.getCurrent() will return null in all other Threads than the Request Thread. Therefore you'll need to store the ui instance in the view or in the thread. Here is a good example of that.

Last updated on Jan, 6th 2020
Agent 100
3 years ago Jan 06, 2020 4:48pm
Kaspar Scherrer
3 years ago Jan 06, 2020 5:01pm
Agent 100
3 years ago Jan 06, 2020 6:27pm
Kaspar Scherrer
3 years ago Jan 07, 2020 7:57am
Agent 100
3 years ago Jan 08, 2020 10:34am

Kaspar Scherrer: That is indeed very strange. Can you run this minified example and verify this as well in a thread with less code?

public class ChartThread extends Thread {
    private UI ui;
    public ChartThread (UI ui) {
	    system.out.printl("Constructor - ui == null: "+ ui == null);
		this.ui = ui;
	}
	
	@Override
	public void run() {
	    system.out.printl("Run - ui == null: "+ ui == null);
	}
}

And if that really doesnt work,you should show how you use the ChartThread (where and how do you initialize it? how do you update isRunning?).

There is also another way of using ui in a background thread - I made a small helper class for this which looks like this:

public class VaadinBackgroundThread {
    public static Thread createThread(Runnable runnable){
        final UI ui = UI.getCurrent();
        final VaadinSession session = VaadinSession.getCurrent();
        final VaadinService service = VaadinService.getCurrent();
        if (ui == null || session == null || service == null) {
            throw new RuntimeException("Neither UI nor VaadinSession nor VaadinService can be null at this point!");
        }
        return new Thread(() -> {
            UI.setCurrent(ui);
            VaadinSession.setCurrent(session);
            VaadinService.setCurrent(service);
            runnable.run();
        });
    }
}

By setting the CurrentUI within the new Thread, you can actually call UI.getCurrent() inside the runnable (same with VaadinSession and VaadinService). And you would use it like this

Thread chartThread = VaadinBackgroundThread.createThread(() -> {
    while(isRunning.get() == true) {
	    ...
		UI.getCurrent().access(() -> {
			...
		});
	}
});
// TODO: chartThread.setUncaughtExceptionHandler(..)
chartThread.start();

do this in the view with the charts. You can now also directly access all the input fields and don't have to extrapolate them out of a layout.

Disclaimer: This is not the standard way of doing it, and it is not mentioned anywhere. The "best" way of doing it would be like you did in your last posted code.

hi! I have read your message. I will give you a reply later.

Agent 100
3 years ago Jan 08, 2020 4:14pm

Kaspar Scherrer: I found the documentation: https://vaadin.com/docs/v14/flow/advanced/tutorial-push-access.html

you also need to have a @Push annotation on the view for it to work.

Edit: I just saw your (now removed) initial response in my inbox, with all your code. The attempt was almost perfect, but you forgot this line in the constructor: this.ui = ui;. This is why it wasnt null in the constructor but in the run() method it was null.

Hi! I tried @Push annotation in my MainView and now the view updates! Thank you!