Страницы

Поиск по вопросам

четверг, 19 декабря 2019 г.

Использование метода sleep()

#java #многопоточность #sleep


Всем добрый день. Нужен совет: программа должна менять надпись на кнопке последовательно
от "10" до "0". Чтобы каждая смена надписи происходила с небольшим интервалом я использовал
метод sleep().

В итоге после нажатия кнопки прога подвисает и затем сразу выдает "0". В чём может
быть проблема? Кусок кода представлен ниже.

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


Ответы

Ответ 1



Добро пожаловать в увлекательный мир UI-программирования! Вам придётся немного переучиться: здесь всё не так, как в программах командной строки. Здесь все фоновые задания, связанные с интерфейсом, происходят не немедленно, как только вы скомандовали, а вперемешку с вашей работой. Всё это происходит в фиксированном потоке, так называемом UI-потоке. Что происходит в вашем коде? Вы блокируете UI-поток на полсекунды, затем устанавливаете текст кнопки. Устанавливается внутренний флаг в графической библиотеке, который говорит «когда будет свободная минутка, надо обновить button». Вы немедленно снова блокируете UI-поток на полсекунды, и переустанавливаете текст кнопки. Поскольку «свободная минутка» (она же «idle loop») так и не наступила, текст обновиться не успел. Кроме того, на время блокировки некому обрабатывать события от мыши и клавиатуры (потому что UI-поток занят sleep'ом), так что программа выглядит зависшей. Затем вы опять устанавливаете текст кнопки, это ничего не меняет, так как флаг, указывающий необходимость обновления, уже взведён. И так далее, 11 раз. В конце-концов, когда ваш цикл закончился, UI-поток наконец-то освободился, и может отрисовать ваши изменения. Вы наконец-то видите 0. В чём суть проблемы? Вы не должны совершать длинные операции в UI-потоке. Thread.sleep — одна из таких операций, но многие ещё и читают файлы, грузят данные из сети или обращаются к базе данных. Вы имеете право загружать UI-поток работой лишь на несколько миллисекунд. На всё время длинной операции, бегущей в UI-потоке, приложение будет выглядеть зависшим, и обработчики UI-событий вызываться не будут. Такое поведение программы сразу превращает её в студенческую поделку. Обновление UI, реакция на мышь, перерисовка контролов — всё происходит в UI-потоке, в тот момент, когда этот поток ничем не занят. Хорошая программа с UI должна быть событийно-ориентированной, а не императивной: вы должны не сами рулить ходом программы, а лишь реагировать на события короткими по времени обработчиками. Что нужно делать? Есть два пути. Простой путь, который вполне подходит для ваших целей: не блокируете UI-поток, а используете таймер, который идёт с вашей UI-библиотекой. Он вызовет ваш обработчик в нужное время, вы установите там текст кнопки, и закончите обработку. тем самым вы отпустите UI-поток, чтобы он смог обновить UI. Сложный путь, который применяется, если вам действительно нужно выполнить длительную операцию. В этом случае вы создаёте отдельный поток (thread), в котором и выполняете нужную операцию. Результаты работы вы в нужный момент посылаете в UI-поток, который должен просто обновить UI. Заметьте, что в этом случае программирование становится намного сложнее, так как вам придётся заботиться о синхронизациях, блокировках и коммуникации между потоками (просто глобальная переменная не катит). Но для вашего случая это лишнее, вполне хватит простого таймера.

Ответ 2



А так если? 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();

Комментариев нет:

Отправить комментарий