Форум программистов, компьютерный форум, киберфорум
Программирование Android
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/6: Рейтинг темы: голосов - 6, средняя оценка - 4.67
0 / 0 / 0
Регистрация: 24.12.2017
Сообщений: 18

Синхронизация вычислений рабочего потока и отрисовки в UI потоке

30.01.2018, 21:32. Показов 1367. Ответов 10
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
В общем в Ui потоке должна идти пошаговая отрисовка ячеек, которые лежат в GridView, а в рабочем созданном потоке производятся вычисления ячеек и соответственно после каждой итерации вычислений должна происходить отрисовка.
Я реализовал это через post, но в процесса работы все таки отрисовываются не совсем корректно. Такое ощущение как будто поток интерфейса не успевает обработать сообщение и перерисовать элементы, а рабочий поток уже переходит на другую итерацию вычислений, хотя насколько я понимаю, все должно работать синхронно.
Вот пример как я сделал:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
final Timer executor = new Timer();
        executor.schedule(new TimerTask() {
            @Override
            public void run() {
                if(isBeingDrawn == false){
                    
                    //---тут вычисления
 
                    //---флаг говорит что идет отрисовка
                    isBeingDrawn = true;
 
                    //---собственно синхронизирую
 
                    gridView.post(new Runnable() {
                        @Override
                        public void run() {
 
                            //---тут он перерисовывает в UI потоке, насколько я понял
                            adapter.notifyDataSetChanged();
 
                            //---и далее говорит что отрисовка закончилась
                           //---чтобы продолжить вычисления 
                            isBeingDrawn = false;
                        }
                    });
 
                }
            }
        }, 0, 20);
    }
И вот такой вопрос: правильно я понимаю что в UI потоке при обработке сообщения из рабочего потока сначала адаптер уведомляет о изменении данных и запрашивает перерисовать, а после флагу присваивается значение false, чтобы рабочий поток продолжил вычисления? Или у меня есть ошибки? Заранее спасибо за ответ
П.С. первый раз спрашиваю на форму, так что извиняйте, если неправильно оформил))
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
30.01.2018, 21:32
Ответы с готовыми решениями:

Создать дочернее окно в новом потоке для отрисовки рисунка
Как создать дочернее окно в новом потоке?мне в дочернем окне надо рисовать. Я запускаю так Thread thr = new Thread(newForm); ...

Создание отдельного потока для отрисовки змейки
partial class View : UserControl { Model model; public View(Model model) { ...

Показывать ProgressBar вычислений, запущенных в отдельном потоке
На главной форме есть кнопка при нажатии создается новый поток: private void button1_Click(object sender, RoutedEventArgs e) { ...

10
MiThEoN
 Аватар для VASSUV
466 / 323 / 42
Регистрация: 31.10.2009
Сообщений: 546
Записей в блоге: 2
31.01.2018, 05:30
Попробуйте так:
Java
1
2
3
4
5
6
7
8
9
10
11
new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message inputMessage) {
         //---тут он перерисовывает в UI потоке, насколько я понял
         gridview.getAdapter().notifyDataSetChanged();
 
         //---и далее говорит что отрисовка закончилась
         //---чтобы продолжить вычисления
         isBeingDrawn = false;
     }
};
1
0 / 0 / 0
Регистрация: 24.12.2017
Сообщений: 18
01.02.2018, 00:01  [ТС]
Цитата Сообщение от VASSUV Посмотреть сообщение
Попробуйте так:
JavaВыделить код
1
2
3
4
5
6
7
8
9
10
11
new Handler(Looper.getMainLooper()) {
* * @Override
* * public void handleMessage(Message inputMessage) {
* * * * *//---тут он перерисовывает в UI потоке, насколько я понял
* * * * *gridview.getAdapter().notifyDataSetChan ged();
//---и далее говорит что отрисовка закончилась
* * * * *//---чтобы продолжить вычисления
* * * * *isBeingDrawn = false;
* * *}
};
К сожалению таким способом он просто отказывается перерисовывать картинку и виснет при уведомлении адаптера
0
MiThEoN
 Аватар для VASSUV
466 / 323 / 42
Регистрация: 31.10.2009
Сообщений: 546
Записей в блоге: 2
01.02.2018, 00:03
Зачем вам так часто нужно обновление? Делайте обновление допустим раз в 1 секунду
0
0 / 0 / 0
Регистрация: 24.12.2017
Сообщений: 18
01.02.2018, 01:32  [ТС]
Цитата Сообщение от VASSUV Посмотреть сообщение
Зачем вам так часто нужно обновление? Делайте обновление допустим раз в 1 секунду
Да, это конечно поможет, но смысл как раз в том, чтобы была синхронизация. В любом случае вопрос можно считать разрешенным, тк как оказалось все работает синхронно, а не очень корректное отображение скорее всего из-за плохо оптимизированного адаптера. Нужно будет еще что-то придумывать для улучшения оптимизации В любом случае, спасибо за ответы
0
MiThEoN
 Аватар для VASSUV
466 / 323 / 42
Регистрация: 31.10.2009
Сообщений: 546
Записей в блоге: 2
01.02.2018, 13:28
Вы создаете handler или runnable чаще чем они успевают выполнится. Потому что ваши вычисления легче чем запуск этих вставок на ui поток.
Если бы Ваши вычисления выполнялись допустим больше секунды, не было бы и проблем

Добавлено через 7 часов 1 минуту
Java
1
2
                    //---флаг говорит что идет отрисовка
                    isBeingDrawn = true;
Вставте сюда Thread.sleep()

Java
1
2
3
                    //---флаг говорит что идет отрисовка
                    Thread.sleep(3000);
                    isBeingDrawn = true;
И постмотрите что изменится
0
0 / 0 / 0
Регистрация: 24.12.2017
Сообщений: 18
03.02.2018, 22:28  [ТС]
Цитата Сообщение от VASSUV Посмотреть сообщение
Вы создаете handler или runnable чаще чем они успевают выполнится. Потому что ваши вычисления легче чем запуск этих вставок на ui поток.
Если бы Ваши вычисления выполнялись допустим больше секунды, не было бы и проблем
Да на самом деле при паузе в 200 миллисек уже работает корректно, но все же я не совсем вас понял. У меня не может создаваться еще один Runnable, если первый еще не завершен(по крайней мере действия в нём).

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
executor.schedule(new TimerTask() {
            @Override
            public void run() {
                if(isBeingDrawn == false){
                    
                    //---тут вычисления
 
                    //---флаг говорит что идет отрисовка
                    isBeingDrawn = true;
 
                    //---собственно синхронизирую
 
                    gridView.post(new Runnable() {
                        @Override
                        public void run() {
 
                            //---тут он перерисовывает в UI потоке, насколько я понял
                            adapter.notifyDataSetChanged();
 
                            //---и далее говорит что отрисовка закончилась
                           //---чтобы продолжить вычисления 
                            isBeingDrawn = false;
                        }
                    });
 
                }
            }
        }, 0, 20);
Рабочий поток по сути ничего не будет делать, тк не сможет зайти в секцию после if если флаг еще не возвращен в состояние false из UI потока, который будет возвращен только после adapter.notifyDataSetChanged(), те перерисовки экрана. Ну и соответственно это гарантирует ситуацию, когда новое сообщение для перерисовки будет отправляться только после успешного завершения текущей и установки флага в false.
0
MiThEoN
 Аватар для VASSUV
466 / 323 / 42
Регистрация: 31.10.2009
Сообщений: 546
Записей в блоге: 2
03.02.2018, 23:33
Новый runnable это как новая инъекция своего кода в ui поток.
А теперь представьте что вы делаете эти инъекции постоянно в цикле без какой либо задержки
Сама инъекция уже требует времени из ui потока даже если ни какого кода выполнятся не будет
И получается что вы забивает ui поток этими инъекциями.
Поток забивают не ваши вычисления, и даже не отрисовка. А именно эти инъекции

И под инъекцией я предполагаю не прямой запуск вашего кода на ui, а всегда отложенный запуск до момента появления свободного вычислительного времени на ui потоке.

Никогда не запускайте runnable в цикле. Возьмите себе за правило такой подход.

Какого рода вычисления у вас? И какие данные переходят из потока в поток?
Может придумаем для вас решение получше

Добавлено через 2 минуты
Можете убедиться в моих словах путем логировани. И по времени посмотрите что где и сколько раз запускается
0
0 / 0 / 0
Регистрация: 24.12.2017
Сообщений: 18
04.02.2018, 22:24  [ТС]
Цитата Сообщение от VASSUV Посмотреть сообщение
Какого рода вычисления у вас? И какие данные переходят из потока в поток?
Может придумаем для вас решение получше
game of life клеточная игра) Ну по сути при запуске в параллельный поток передается два массива объектов с полем boolean, а также еще некоторые переменные, точнее все это находится в классе логики, и уже в методе запускается этот поток для расчетов, используя данные поля и отправляя эти самые инъекции в графический поток для отрисовки. Соответственно делать итерации изменений поля в анимации имеет смысл когда fps ну хотя бы 20-30, те хотябы с задержкой не более чем 50мс. Сами вычисления легкие по сути. И вот я тогда даже не знаю каким образом можно реализовать, если вариант с циклом так загружает главный поток
Вот код метода с параллельным расчетом:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
void startGame(final GridView gameField,
                   final CellsAdapter adapter,
                   final ToggleButton gameRunningSwitch,
                   final Button oneStepButton)
    {
        isGameRunning = true;
        oneStepButton.setEnabled(false);
        final Timer gameExecutionTimer = new Timer();
        gameExecutionTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                if(!isBeingDrawn){
                    //------------------make a calculation part------------
                    if(unlimitedBorders){
                        makeOneStepUnlimitedBorders();
                    }
                    else{
                        makeOneStep();
                    }
                    //-------------------redraw in main thread-------------
                    isBeingDrawn = true;
                    gameField.post(new Runnable() {
                        @Override
                        public void run() {
                            adapter.notifyDataSetChanged();
                            isBeingDrawn = false;
                        }
                    });
                    //-------------------------checking condition------------------
                    adjGenerationsHaveDifference = false;
                    for (int i = 0; i < rowAmount; i++) {
                        for (int j = 0; j < columnAmount; j++) {
                            if (currentGeneration[i][j].isAlive() != gameFieldData[i][j].isAlive()) {
                                adjGenerationsHaveDifference = true;
 
                            }
                        }
                    }
                    if(!isGameRunning){
                        oneStepButton.post(new Runnable() {
                            @Override
                            public void run() {
                                oneStepButton.setEnabled(true);
                            }
                        });
                        gameExecutionTimer.cancel();
                        gameExecutionTimer.purge();
                        return;
                    }
                    if ((!adjGenerationsHaveDifference) || (aliveCellsAmount == 0)) {
                        gameRunningSwitch.post(new Runnable() {
                            @Override
                            public void run() {
                                gameRunningSwitch.setChecked(false);
                            }
                        });
                        oneStepButton.post(new Runnable() {
                            @Override
                            public void run() {
                                oneStepButton.setEnabled(true);
                            }
                        });
                        isGameRunning = false;
                        gameExecutionTimer.cancel();
                        gameExecutionTimer.purge();
                    }
                }
            }
        }, 0, 50);
    }
Хотя конечно если увеличить количество строк и столбцов уже примерно до 30, то уже начинает явно тормозить даже без непрерывной анимации.
0
MiThEoN
 Аватар для VASSUV
466 / 323 / 42
Регистрация: 31.10.2009
Сообщений: 546
Записей в блоге: 2
05.02.2018, 09:47
Мое мнение такое. Поставь себе либу RxJava. Хорошо что есть по ней много туториалов, без труда сможешь вникнуться.

Как подключишь, придется написать что то вроде этого, не более
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        AtomicInteger nextValue = new AtomicInteger(1);
        Disposable disposable = Observable.<AtomicInteger>create(o -> {
            while(!o.isDisposed()) {
                nextValue.incrementAndGet();
                /** Здесь сделать вычисления, Желательно вынести в отдельный метод **/
                o.onNext(nextValue);
            }
            o.onComplete();
        })
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        v -> refreshUi(v),
                        e -> e.printStackTrace(),
                        () -> System.out.println("Completed")
                );
Java
1
2
3
    private void refreshUi(AtomicInteger v) {
        /**     Как то обновляешь UI    **/ 
    }
Java
1
2
3
        /**    Когда нужно будет завершить  
               Стоит вызвать dispose()        **/
        disposable.dispose();
Если будут еще фризы, то поставить после onNext(***) задержку в 30мс

Да и, у тебя есть массивы данных, которые как я понял обновляются в другом потоке, и выводятся на UI
Если они хоть как то будут обновляться на UI, их сразу следует сделать другим типом AtomicArray(точно не помню), чтобы не было коллизий данных между потоками
1
0 / 0 / 0
Регистрация: 24.12.2017
Сообщений: 18
06.02.2018, 18:53  [ТС]
Спасибо, буду читать и разбираться
Насчет обновления массивов. В том месте, где используется параллельный поток, они обновляются только в нём во избежание как раз конфликтов между потоками.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
06.02.2018, 18:53
Помогаю со студенческими работами здесь

Выполнение длительных вычислений и операций в отдельном потоке
Добрый вечер. Возникла проблема с вычислениями. Из базы данных (файл) читаются числа и выполняются с ними операции.....

Закрыть форму во втором потоке при окончании вычислений в первом
Утро доброе. есть главная форма, в ней выполняются долгие вычисления (соответственно программа - AutoCAD - виснет). Запихивал эти...

Синхронизация асинхронных событий в одном потоке
Добрый день! Работаю с веб сервисами. Столкнулся со следующей проблемой на стороне клиента: для получения одного полного бизнес объекта...

Синхронизация потока
Имеется поток, ошибка в wsocket1.Как синхронизовать? procedure tzon.execute; var t:integer; begin WSocket1.Sendline('JOIN...

база рабочего потока
в литературе нашел ссылку на шаблон approve4.ntf из стандартной поставки Lotus Notes 4.x в часности Lotus Notes 4.5. если у кого завалялась...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
Автозаполнение реквизита при выборе элемента справочника
Maks 27.03.2026
Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. При выборе "Спецтехники" (Тип Справочник. Спецтехника), заполняется. . .
Сумматор с применением элементов трёх состояний.
Hrethgir 26.03.2026
Тут. https:/ / fips. ru/ EGD/ ab3c85c8-836d-4866-871b-c2f0c5d77fbc Первый документ красиво выглядит, но без схемы. Это конечно не даёт никаких плюсов автору, но тем не менее. . . всё может быть. . .
Автозаполнение реквизитов при создании документа
Maks 26.03.2026
Программный код из решения ниже размещается в модуле объекта документа, в процедуре "ПриСозданииНаСервере". Алгоритм проверки заполнения реализован для исключения перезаписи значения реквизита,. . .
Команды формы и диалоговое окно
Maks 26.03.2026
1. Команда формы "ЗаполнитьЗапчасти". Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. В качестве источника данных. . .
Кому нужен AOT?
DevAlt 26.03.2026
Решил сделать простой ланчер Написал заготовку: dotnet new console --aot -o UrlHandler var items = args. Split(":"); var tag = items; var id = items; var executable = args;. . .
Отправка уведомления на почту при изменении наименования справочника
Maks 24.03.2026
Программная отправка письма электронной почты на примере изменения наименования типового справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной. . .
модель ЗдравоСохранения 5. Меньше увольнений- больше дохода!
anaschu 24.03.2026
Теперь система здравосохранения уменьшает количество увольнений. 9TO2GP2bpX4 a42b81fb172ffc12ca589c7898261ccb/ https:/ / rutube. ru/ video/ a42b81fb172ffc12ca589c7898261ccb/ Слева синяя линия -. . .
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru