Not update button's caption when start countdown

In my Vaadin (7.3) project when click button then I need:

  1. Start countdown (10 seconds)

2.Replace button’s caption by left seconds (10,9,8 and so on)

I try this:

private Button buttonNext, buttonSendSMS;

private void runCountDown() {
        logger.info("countDown_start");
        buttonSendSMS.setEnabled(false);
        final Timer timer = new Timer();
        
        timer.scheduleAtFixedRate(new TimerTask() {
            int leftSeconds = 10;

            public void run() {
                leftSeconds--;

                UI.getCurrent().access(new Runnable() {

                    @Override
                    public void run() {
                        logger.info("leftSeconds = " + leftSeconds);
                        buttonSendSMS.setCaption(leftSeconds + "");
                    }
                });

                if (leftSeconds < 0) {
                    logger.info("countDown_finish");
                    timer.cancel();
                    buttonSendSMS.setEnabled(true);
                    new MessageService(getWzContext().getLang());
                    buttonSendSMS.setCaption(MessageService.getMessage("resend.sms"));
                }
            }
        }, 0, 1000);
    }

When click button here log:

INFO] 12.01.2021 17:35:58.112 [Timer-0]
com.myproject.client.ui.wz.SmsCodeStepWz$2$1.run(SmsCodeStepWz.java:202) 
   leftSeconds = 9
INFO] 12.01.2021 17:35:59.111 [Timer-0]
com.myproject.client.ui.wz.SmsCodeStepWz$2$1.run(SmsCodeStepWz.java:202) 
   leftSeconds = 8
[INFO]
12.01.2021 17:36:00.110 [Timer-0]
com.myproject.client.ui.wz.SmsCodeStepWz$2$1.run(SmsCodeStepWz.java:202) 
   leftSeconds = 7
[INFO]
12.01.2021 17:36:01.110 [Timer-0]
com.myproject.client.ui.wz.SmsCodeStepWz$2$1.run(SmsCodeStepWz.java:202) 
   leftSeconds = 6
[INFO]
12.01.2021 17:36:02.111 [Timer-0]
com.myproject.client.ui.wz.SmsCodeStepWz$2$1.run(SmsCodeStepWz.java:202) 
   leftSeconds = 5
[INFO]
12.01.2021 17:36:03.110 [Timer-0]
com.myproject.client.ui.wz.SmsCodeStepWz$2$1.run(SmsCodeStepWz.java:202) 
   leftSeconds = 4
[INFO]
12.01.2021 17:36:04.110 [Timer-0]
com.myproject.client.ui.wz.SmsCodeStepWz$2$1.run(SmsCodeStepWz.java:202) 
   leftSeconds = 3

But on Web page replace button’s caption to 9. Nice.

But after one second NOT REPLACE by 8. And nothing happened. Button’s caption is only 9.

As you can see I try to update button’s caption on UI thread but it not help.

I just tried your code with Vaadin version 8.12.0 and it works fine. It sounds like you might not have Server Push properly configured. In the simplest case, you need to add @Push annotation on your class for your code to work.

Tarek Oraby:
I just tried your code with Vaadin version 8.12.0 and it works fine. It sounds like you might not have Server Push properly configured. In the simplest case, you need to add @Push annotation on your class for your code to work.

I try with @Push but it not help

import com.vaadin.annotations.Push;
@SuppressWarnings("serial")
@Push
public class SmsCodeStepWz extends RootStep {
...
}

@SuppressWarnings("serial")
public abstract class RootStep extends VerticalLayout {

P.S. Vaadin 7.3.6

The @Push annotation should be on the UI class.

Yes, please note what Olli said.

The following similar example works fine in Vaadin 7.7.17

@Push
public class MyUI extends UI {

    @Override
    protected void init(VaadinRequest vaadinRequest) {
        final VerticalLayout layout = new VerticalLayout();
        setContent(layout);

        Button button = new Button("", e -> Notification.show("Hello world"));
        layout.addComponents(button);

        button.setEnabled(false);
        final Timer timer = new Timer();

        timer.scheduleAtFixedRate(new TimerTask() {
            int leftSeconds = 10;

            @Override
            public void run() {
                leftSeconds--;

                UI.getCurrent().access(() -> button.setCaption(leftSeconds + ""));

                if (leftSeconds < 1) {
                    timer.cancel();
                    UI.getCurrent().access(() -> {
                        button.setCaption("Click me");
                        button.setEnabled(true);
                    });
                }
            }
        }, 0, 1000);

    }

    @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
    @VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
    public static class MyUIServlet extends VaadinServlet {
    }
}

Please also note that the following lines in your code should be also enclosed in a UI.getCurrent().access(() -> {}) block

buttonSendSMS.setEnabled(true);
new MessageService(getWzContext().getLang());
buttonSendSMS.setCaption(MessageService.getMessage("resend.sms"));

Tarek Oraby:
Please also note that the following lines in your code should be also enclosed in a UI.getCurrent().access(() -> {}) block

buttonSendSMS.setEnabled(true);
new MessageService(getWzContext().getLang());
buttonSendSMS.setCaption(MessageService.getMessage("resend.sms"));

I try this:

@SuppressWarnings("serial")
public class SmsCodeStepWz extends VerticalLayout {
   private Button buttonNext, buttonSendSMS;

	@Override
	protected void initContent() {
		buttonSendSMS.addClickListener(new Button.ClickListener() {

			@Override
			public void buttonClick(ClickEvent event) {
				logger.debug("Click_send_sms_button");
				MyUI myUI = new MyUI();
	            myUI.initTimer();
			}
		});
	}

	
				
	@Push
	public class MyUI extends UI {

		public void initTimer() {
			logger.info("initTimer:");
			buttonSendSMS.setEnabled(false);
			final Timer timer = new Timer();

			timer.scheduleAtFixedRate(new TimerTask() {
				int leftSeconds = 10;

				@Override
				public void run() {
					leftSeconds--;

					UI.getCurrent().access(new Runnable() {

						@Override
						public void run() {
							logger.info("leftSeconds = " + leftSeconds);
							buttonSendSMS.setCaption(leftSeconds + "");
						}
					});

					if (leftSeconds < 1) {
						UI.getCurrent().access(new Runnable() {

							@Override
							public void run() {
								timer.cancel();
								logger.info("leftSeconds = " + leftSeconds);
								buttonSendSMS.setEnabled(true);
								new MessageService(getWzContext().getLang());
								buttonSendSMS.setCaption(MessageService.getMessage("resend.sms"));
							}
						});
					}
				}
			}, 0, 1000);
		}

		@Override
		protected void init(VaadinRequest request) {
			logger.info("init:");
		}
	}
}

But it not help.

In log:


INFO] 13.01.2021 12:50:43.098 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$1.run(SmsCodeStepWz.java:256) 
    leftSeconds = 9
[INFO]
 13.01.2021 12:50:44.096 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$1.run(SmsCodeStepWz.java:256) 
    leftSeconds = 8
[INFO]
 13.01.2021 12:50:45.097 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$1.run(SmsCodeStepWz.java:256) 
    leftSeconds = 7
[INFO]
 13.01.2021 12:50:46.096 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$1.run(SmsCodeStepWz.java:256) 
    leftSeconds = 6
[INFO]
 13.01.2021 12:50:47.096 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$1.run(SmsCodeStepWz.java:256) 
    leftSeconds = 5
[INFO]
 13.01.2021 12:50:48.097 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$1.run(SmsCodeStepWz.java:256) 
    leftSeconds = 4
[INFO]
 13.01.2021 12:50:49.096 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$1.run(SmsCodeStepWz.java:256) 
    leftSeconds = 3
[INFO]
 13.01.2021 12:50:50.096 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$1.run(SmsCodeStepWz.java:256) 
    leftSeconds = 2
[INFO]
 13.01.2021 12:50:51.097 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$1.run(SmsCodeStepWz.java:256) 
    leftSeconds = 1
[INFO]
 13.01.2021 12:50:52.096 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$1.run(SmsCodeStepWz.java:256) 
    leftSeconds = 0
[INFO]
 13.01.2021 12:50:52.098 [Timer-0]
 com.myprojectx.wz.SmsCodeStepWz$MyUI$1$2.run(SmsCodeStepWz.java:267) 
    leftSeconds = 0

As you can see the countdown is decrement, but in UI it not update. Show only digit 9 on button’s caption.

P.S>Vaadin 7.3.6

I’m at loss with your code. It doesn’t show how you are adding the Buttons to your VerticalLayout, nor does it show the parent UI of the VerticalLayout.

If I would guess, you are missing @Push on the UI that adds SmsCodeStepWz as one of its child-components (which you don’t show us here).

Tarek Oraby:
I’m at loss with your code. It doesn’t show how you are adding the Buttons to your VerticalLayout, nor does it show the parent UI of the VerticalLayout.

If I would guess, you are missing @Push on the UI that adds SmsCodeStepWz as one of its child-components (which you don’t show us here).

here additional code:



@SuppressWarnings("serial")
public abstract class RootStep extends VerticalLayout {


public RootStep() {
        postInitContent()
        nextBlock = new NextRefresh(isRefreshRequired(), getNextActionTitle());
		nextBlock.setNextListener(nextListener);
		addComponent(nextBlock);
}

protected void postInitContent() {};
}

@SuppressWarnings("serial")
public class NextRefresh extends VerticalLayout {
  public static String COMMON_HORIZONTAL_LEFT = "COMMON_HORIZONTAL_LEFT";

}

@SuppressWarnings("serial")
@Push
public class SmsCodeStepWz extends RootStep { 
       private Button buttonNext, buttonSendSMS;
       private HorizontalLayout commonHorizontalLayout;


        @Override
	protected void initContent() {
	    buttonSendSMS = new Button(MessageService.getMessage("resend.sms"));
		buttonSendSMS.addClickListener(new Button.ClickListener() {

			@Override
			public void buttonClick(ClickEvent event) {
				logger.debug("Click_send_sms_button");
				MyUI myUI = new MyUI();
	            myUI.initTimer();
			}
		});
	}

       @Override
	protected void postInitContent() {
		Button nextButton = (Button) findById(this, NextRefresh.NEXT_BUTTON_ID);
		if (nextButton != null) {
			nextButton.setVisible(false);
		}
		commonHorizontalLayout = (HorizontalLayout) findById(this, NextRefresh.COMMON_HORIZONTAL_LEFT);
		commonHorizontalLayout.addComponent(buttonSendSMS);

		Label labelGap = new Label("");
		labelGap.setWidth("10px");
		commonHorizontalLayout.addComponent(labelGap);
	}


	@Push
	public class MyUI extends UI {

		public void initTimer() {
			logger.info("initTimer:");
			buttonSendSMS.setEnabled(false);
			final Timer timer = new Timer();

			timer.scheduleAtFixedRate(new TimerTask() {
				int leftSeconds = 10;

				@Override
				public void run() {
					leftSeconds--;

					UI.getCurrent().access(new Runnable() {

						@Override
						public void run() {
							logger.info("leftSeconds = " + leftSeconds);
							buttonSendSMS.setCaption(leftSeconds + "");
						}
					});

					if (leftSeconds < 1) {
						UI.getCurrent().access(new Runnable() {

							@Override
							public void run() {
								timer.cancel();
								logger.info("leftSeconds = " + leftSeconds);
								buttonSendSMS.setEnabled(true);
								new MessageService(getWzContext().getLang());
								buttonSendSMS.setCaption(MessageService.getMessage("resend.sms"));
							}
						});
					}
				}
			}, 0, 1000);
		}

		@Override
		protected void init(VaadinRequest request) {
			logger.info("init:");
		}
}



The RootStep is abstract class.
And here how I add SmsCodeStepWz

public class UbUI extends UI {


@Override
protected void init(final VaadinRequest request) {
  
	SmsCodeStepWz smsCodeStep = new SmsCodeStepWz();
	smsCodeStep.setCallback(smsCallback);
	addStep(smsCodeStep);

	}

}

How is RootStep added to the UI?

Tarek Oraby:
How is RootStep added to the UI?

I was updated my response

Could you try adding @Push on UbUI ?

Tarek Oraby:
Could you try adding @Push on UbUI ?

I found solution.

This method:


UI.getCurrent().setPollInterval(-1);

Was called before start my countdown. But when I call this method after finish my countdown then then button’s caption success updated 9,8,7 and so on. Nice.

The question is:Why update of button is depend on ?

UI.getCurrent().setPollInterval(-1);

Here result worked version:

private void runCountDown() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					while (true) {
						
						countDownSec--;
						UI.getCurrent().access(new Runnable() {

							@Override
							public void run() {
								logger.info("countDownSec = " + countDownSec);
								buttonSendSMS.setCaption(countDownSec + "");
							}
						});
						Thread.sleep(1000);
						if (countDownSec < 1) {
							break;
						}
					} // end while
   		           UI.getCurrent().setPollInterval(-1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

			}
		}).start();
	}

As far as I know, polling should not affect Server Push. Could be a bug in the older version you are using.