Good day everyone. Need advice: the program should change the inscription on the button consistently from "10" to "0". To make each change of the inscription take place at a short interval, I used the sleep () method.

In the end, after pressing the button, the program hangs and then immediately issues "0". What could be the problem? A piece of code is presented below.

try { for (int i = 10; i > -1; i--) { Thread.sleep(500); String iString = String.valueOf(i); button.setText(iString); } } catch (InterruptedException qq) { qq.printStackTrace(); } 

    2 answers 2

    Welcome to the fascinating world of UI programming! You will have to retrain a bit: here everything is not the same as in the command line programs. Here, all background tasks related to the interface do not occur immediately, as soon as you have commanded, but in tandem with your work. All this happens in a fixed thread, the so-called UI thread.

    What happens in your code?

    1. You block the UI thread for half a second, then set the button text. An internal flag is set in the graphic library that says "when there is a free minute, you need to update the button".
    2. You immediately block the UI stream for half a second, and reinstall the button text. Since the “free time” (the “idle loop”) did not come, the text did not have time to be updated. In addition, there is no one to handle mouse and keyboard events at the time of the lock (because the UI thread is busy for sleep ), so the program looks hung.
    3. Then you install the button text again, this does not change anything, since the flag indicating the need for updating is already cocked.
    4. And so on, 11 times.
    5. In the end, when your loop is over, the UI thread is finally free, and can draw your changes. You finally see 0.

    What is the problem? You do not have to perform long operations in a UI thread. Thread.sleep is one such operation, but many also read files, load data from a network, or access a database. You have the right to load the UI stream for only a few milliseconds. For the entire time of a long operation running in a UI thread, the application will appear to hang, and UI event handlers will not be called. This behavior of the program immediately turns it into a student crafts.

    Updating the UI, the reaction to the mouse, the redrawing of the controls - everything happens in the UI stream, at that moment when this stream is not busy at all. A good program with a UI should be event-oriented, not imperative: you should not steer the program yourself, but only respond to events with short handlers.

    What do we have to do? There are two ways. A simple way, which is quite suitable for your purposes: do not block the UI stream, but use the timer that goes with your UI library. It will call your handler at the right time, you will set the button text there, and finish processing. thus, you release the UI flow so that it can update the UI.

    Difficult path that applies if you really need to perform a lengthy operation. In this case, you create a separate thread (thread), in which and perform the desired operation. At the right moment, you send the results of the work to the UI stream, which should simply update the UI. Note that in this case, programming becomes much more difficult, since you have to take care of synchronization, locking and communication between threads (just the global variable does not roll). But for your case, this is superfluous, a simple timer is enough.

    • Wow! Thanks for the detailed answer) - pop-suxx
    • @ pop-suxx: please! - VladD
    • @VladD "Note that in this case, programming becomes much more difficult, since you have to take care of synchronizations, locks and communication between threads (just a global variable does not roll)." - does not Java really provide a simpler way to interact with the UI stream (like the Sharpovsky Invoke , for example)? - Qwertiy ♦
    • Well, the concept like SynchronizationContext at the level of language is not present. UI libraries usually provide an abstraction of invoking a job on its thread. For example, SwingUtilities.invokeLater . I meant it. In any case, we need synchronization (mutexes). - VladD

    And if so?

     Thread th = new Thread(new Runnable() { for (int i = 10; i > -1; i--) { String iString = String.valueOf(i); button.setText(iString); sleep(1000); } }); th.start(); 
    • But from a separate thread can not access the UI. Or is it only related to android? - Helisia
    • one
      Of course, it is impossible! And Android has nothing to do with it. In this case, it is necessary to call the runOnUiThread (Runnable) method from the context of the UI thread; - AseN