Asynchronous Updates

This section describes to use server push from your application code. See Server Push Configuration for an overall description on what server push means and how to configure your application to use server push.

Making changes to a UI from another thread and pushing them to the browser requires locking the user session. Otherwise, the UI update done from another thread could conflict with a regular event-driven update and cause either data corruption or deadlocks. Because of this, you may only access an UI using the access() method, which locks the session to prevent conflicts. It takes as parameter a Command to execute while the session is locked.

For example:

ui.access(new Command() {
    @Override
    public void execute() {
        statusLabel.setText(statusText);
    }
});

You also use a simple lambda expression to define your access command.

ui.access(() -> statusLabel.setText(statusText));

If the push mode is manual, you need to push the pending UI changes to the browser explicitly with the push() method.

ui.access(() -> {
    statusLabel.setText(statusText);
    ui.push();
});

Below is a complete example of a case where we make UI changes from another thread.

@Push
@Route("push")
public class PushyView extends VerticalLayout {
    private FeederThread thread;

    @Override
    protected void onAttach(AttachEvent attachEvent) {
        add(new Span("Waiting for updates"));

        // Start the data feed thread
        thread = new FeederThread(attachEvent.getUI(), this);
        thread.start();
    }

    @Override
    protected void onDetach(DetachEvent detachEvent) {
        // Cleanup
        thread.interrupt();
        thread = null;
    }

    private static class FeederThread extends Thread {
        private final UI ui;
        private final PushyView view;

        private int count = 0;

        public FeederThread(UI ui, PushyView view) {
            this.ui = ui;
            this.view = view;
        }

        @Override
        public void run() {
            try {
                // Update the data for a while
                while (count < 10) {
                    // Sleep to emulate background work
                    Thread.sleep(500);
                    String message = "This is update " + count++;

                    ui.access(() -> view.add(new Span(message)));
                }

                // Inform that we are done
                ui.access(() -> {
                    view.add(new Span("Done updating"));
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

When sharing data between UIs or user sessions, you need to consider the message-passing mechanism more carefully, as explained in Creating Collaborative Views.