Search code examples
codenameoneevent-dispatch-thread

How to refresh a counter on the UI without blocking the rest, in codename one?


I try to get a score count on the UI, to be refreshed several times per second. The refresh should not prevent the other elements of the UI from working (Buttons should remain clickable etc.)

I read the doc on the EDT and tried to add a method called from the constructor of the Form:

  private void loopScore() {
        Display.getInstance().callSerially(
                () -> {
                    while (true) {
                        try {
                            MyApplication.score = MyApplication.score + 1;
                            this.gui_Score.setText(String.valueOf(MyApplication.score));
                            Thread.sleep(100);
                        } catch (InterruptedException ex) {
                            //do something
                        }
                    }
                });
    }

But this does not update gui_Score and it blocks the rest of the UI. Help?


Solution

  • A solution is to override the animate method of the Form.

    This method is called at each new cycle of the EDT (which is every millisecond or so) to verify if there is a need to repaint anything.

    Overriding the method allows to insert a line of code updating the text of the Label where the score is:

    @Override
    public boolean animate() {
        if (System.currentTimeMillis() / 1000 > lastRenderedTime / 1000) {
            lastRenderedTime = System.currentTimeMillis();
            computeScore();
            this.gui_Score.setText(String.valueOf(MyApplication.score));
            return true;
        }
        return false;
    
    }
    
    private void computeScore() {
        MyApplication.score = MyApplication.score + 3;
    }
    

    Then, you need to register this animation with the registerAnimated method. I do it from the constructor of the Form:

    public Form1(com.codename1.ui.util.Resources resourceObjectInstance) {
        initGuiBuilderComponents(resourceObjectInstance);
        lastRenderedTime = System.currentTimeMillis();
        registerAnimated(this);
    }
    

    Now the Label with the counter refreshes every second, showing an increment of 3. The rest of the UI remains responsive, nothing is blocking.

    (solution found by fiddling with the animation of a clock demonstrated on this page)