Component not updated from other Thread?

Hi, every one. Please help

I need to update ui component from other thread.

doc: https://vaadin.com/docs/v12/flow/advanced/tutorial-push-access.html

My code is working, but no refresh component in real time(then my child thread finish the job, for update component i need click on any button)

@Push(PushMode.AUTOMATIC)
public class WindowCreateLK  extends Composite<Div> implements RouterLayout{
	WindowCreateLK mainView;
	TextField tfDataFromServer;
	
    public WindowCreateLK(){
	         this.mainView = this;
	
	         tfDataFromServer = new TextField("empty"); 
	         
			 
			 /**
			 * tfDataFromServer updated then click on any button;
			 */
			 Button someButton1 = new Button("Some button2");
			 someButton1.addClickListener(e->{
			 
			 });
			 Button someButton2 = new Button("Some button2");
			 someButton2.addClickListener(e->{
			 
			 });
	
	         getContent().add(tfDataFromServer,someButton1,someButton2);
			 
			 
			 
	         //My Thread
	         MyCustomThread myThread = new MyCustomThread(UI.getCurrent(),context);
             myThread.start(); 
			 
			 
	}

    //inner class
    private static class MyCustomThread extends Thread {
        private final UI ui;
        private final WindowCreateLK mainView;

        private int count = 0;

        public MyCustomThread(UI ui, WindowCreateLK mainView) {
            this.ui = ui;
            this.mainView = mainView;
        }

        @Override
        public void run() {
            try {
                // Update the data for a while
                while (count < 10) {
                    Thread.sleep(500);
                    System.out.println(count);
                    count++;
                }

                // Inform that we are done
                ui.access(() -> {
                    mainView.tfDataFromServer.setValue("SomeData"));
                  
			       //But for view changes, i need click on some component with listener(like button or tab)

                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Can you confirm that push is working by doing a simple button clicklistener that just does e.g.
UI.access calling Thread.sleep(1000) and a Notification?

you seem to have a call to ui.access() within another ui.access(), is that intentional? can you try without?
When creating your custom thread, what is context? shouldn’t it be this?
You don’t need to call ui.push() because the default PushMode is automatic.

Nicklas Karlsson:
Can you confirm that push is working by doing a simple button clicklistener that just does e.g.
UI.access calling Thread.sleep(1000) and a Notification?

 Button btn = new Button("TEST");
        btn.addClickListener(e->{
           UI.getCurrent().access(new Command() {
               @Override
               public void execute() {
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e1) {
                       e1.printStackTrace();
                   }
                   Notification.show("123");//Working
               }
           }) ;
        });

Kaspar Scherrer:
you seem to have a call to ui.access() within another ui.access(), is that intentional? can you try without?
When creating your custom thread, what is context? shouldn’t it be this?
You don’t need to call ui.push() because the default PushMode is automatic.

“you seem to have a call to ui.access() within another ui.access()” - mistake then edit post(update post)

ui.push()” - ok, remove, but :frowning:

You shouldn’t execute the UI.access in the click listener main thread. Instead, start the thread there and use ui.access() to update the UI. Note: you can’t call UI.getCurrent() from a background thread - you must use something like component.getUI() to find the UI instance or store a reference to the UI instance in a variable.

Hi Роман

I tried out your updated code in your first post, and for me it works. I did make other changes however:

  • start the thread not directly in the constructor of the view, instead start it in one of the button clickListeners. While it should work anyway, I want to have full control of when I start my background thread. I want to fully load the page before the background thread even starts.
  • To prove that the ui.access works while the background thread is still running, i “updated the data for another while” after the call to ui.access. This is only for proof and will not be necessary for you of course, just like you wont need the artificial count-increase-loop before the ui.access.
  • I passed this into the constructor of MyCustomThread instead of context

Here is the final code that I used for this, which worked.

@Push
@Route(value = "test")
public class TestView extends Composite<Div> {

    private TextField tfDataFromServer;

    public TestView(){

        tfDataFromServer = new TextField("empty");
        MyCustomThread myThread = new MyCustomThread(UI.getCurrent(), this);

        Button someButton1 = new Button("start myThread");
        someButton1.addClickListener(e->{
            myThread.start();
        });

        getContent().add(tfDataFromServer,someButton1);

    }

    //inner class
    private static class MyCustomThread extends Thread {
        private final UI ui;
        private final TestView testView;

        private int count = 0;

        public MyCustomThread(UI ui, TestView testView) {
            this.ui = ui;
            this.testView = testView;
        }

        @Override
        public void run() {
            try {
                // Update the data for a while
                count = 0;
                while (count < 10) {
                    Thread.sleep(500);
                    System.out.println(count);
                    count++;
                }

                // Inform that we are done
                ui.access(() -> {
                    testView.tfDataFromServer.setValue("SomeData");
                });

                // Update the data for another while
                while (count < 20) {
                    Thread.sleep(500);
                    System.out.println(count);
                    count++;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Thanks for all:)

It didn’t work because several tabs with app were open in the browser