Диалог Vaadin открывается после выполнения метода, а не до

Когда я нажимаю кнопку, я хочу сделать 2 вещи: во-первых, открыть диалоговое окно, а во-вторых, выполнить метод (который находится в файле jar). Проблема в том, что, когда я нажимаю кнопку, сначала выполняется метод, а затем открывается диалоговое окно. Код выглядит примерно так:

button.addClickListener(event -> start()); 

public void start() { 
        dialog.open(); //Second, it opens the Dialog
        methodInJar(); //First it executes this method
    }

Примечание. То же самое происходит независимо от того, является ли это диалоговым окном, уведомлением или каким-либо изменением в интерфейсе.

Кто-нибудь знает, в чем проблема?

Спасибо.

PD. Это целый класс:

package com.example.test;

import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.page.Push;
import com.vaadin.flow.router.Route;

@Route("myView")
@Push
public class MyView extends VerticalLayout {

    private UI ui;
    private Dialog dialog = new Dialog();

    public MyView(){

        addAttachListener(event -> {
            this.ui = event.getUI();
        });
        add(new Button("some button", click -> start()));
    }

    private void start(){
        this.ui.access(() -> {
            dialog.open();
        });
        methodInJarTest();
    }
    
    private void methodInJarTest() {
        try {
            System.out.println("JAR test - 10 seconds pause");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

person Vicente    schedule 10.07.2020    source источник


Ответы (1)


Любые изменения пользовательского интерфейса выполняются после завершения всего обратного обращения к серверу, то есть после того, как кнопки clickListener полностью завершили работу в вашем случае. И поскольку в течение всего прослушивателя кликов пользовательский интерфейс заблокирован, вы даже не можете сделать ui.access во время прослушивания кликов, потому что для этого также требуется блокировка пользовательского интерфейса.

Что вы можете сделать здесь, так это позволить прослушивателю кликов запустить новый поток, в котором вы выполняете тяжелую работу. Это означает, что прослушиватель кликов завершает работу очень быстро и, следовательно, снимает блокировку пользовательского интерфейса. Теперь мы можем выполнять ui.access(...) вызовов из фонового потока, который все еще работает.

Вот как будет выглядеть ваш код

@Route("myView")
@Push
public class MyView extends VerticalLayout {

    private UI ui;
    private Dialog dialog = new Dialog();

    public MyView(){
        // save the ui instance when the view is attached for later reference
        addAttachListener(event -> {
            this.ui = event.getUI();
        });
        add(new Button("some button", click -> start()));
    }

    private void start(){
        new Thread(() -> {
            // UI.getCurrent() would return null in a new Thread, that's why we saved the ui instance during attach of the view.
            ui.access(() -> dialog.open());
            methodInJarTest();
        }).start();
    }

    private void methodInJarTest() {
        try {
            System.out.println("JAR test - 10 seconds pause");
            Thread.sleep(10000);
            ui.access(() -> dialog.add(new Span("methodInJar completed")));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Документы:
@Push
Асинхронные обновления

В целом можно сказать, что вы должны выполнять любую задачу, которая может занять некоторое время внутри фонового потока, чтобы избежать блокировки пользовательского интерфейса.

person kscherrer    schedule 10.07.2020
comment
Привет, кшеррер. Спасибо за ваш быстрый ответ. Я выполнил ваши инструкции в своем проекте, но, к сожалению, проблема не устранена. Я даже создал проект Vaadin my-starter-project всего с одним классом с вашим кодом, но результат снова тот же: он открывает диалоговое окно после того, как метод завершил свое выполнение. Я использую проект Eclipse и Vaadin 10+. Когда я создаю проект, стек технологий - это Spring boot. Любая идея? Еще раз спасибо. - person Vicente; 10.07.2020
comment
вы можете показать код вашего представления? Может, тогда я вижу проблему. Код, который я написал в своем ответе, должен работать. - person kscherrer; 10.07.2020
comment
Конечно, я отредактировал свой исходный вопрос. Я тестирую ваш код в проекте, который содержит только один класс. Спасибо. - person Vicente; 10.07.2020
comment
Я только что попробовал код сам, и он действительно не работает. Я в недоумении! По-видимому, прослушиватель кликов полностью блокирует пользовательский интерфейс до завершения, поэтому ui.access откладывается до тех пор, пока не сможет заблокировать его сам. Решение состоит в том, чтобы поместить тяжелые операции в асинхронный / фоновый поток, чтобы прослушиватель кликов быстро завершил работу, а затем вы выполняете обновления пользовательского интерфейса с ui.access из фонового потока. - person kscherrer; 10.07.2020
comment
Я соответствующим образом отредактировал свой ответ и проверил его и на этот раз - у меня он работает. Я действительно не знал, что прослушиватель кликов блокирует пользовательский интерфейс! Думаю, я здесь много раз давал неправильные советы, если это действительно так ... - person kscherrer; 10.07.2020
comment
Оно работает! Спасибо за ваше исследование и помощь. Я очень благодарен. - person Vicente; 13.07.2020