Форум программистов, компьютерный форум CyberForum.ru

Непонятное поведение многопоточного приложения - Android

Восстановить пароль Регистрация
 
кверти
4 / 4 / 1
Регистрация: 22.09.2013
Сообщений: 136
Завершенные тесты: 2
12.05.2016, 20:00     Непонятное поведение многопоточного приложения #1
Всем добрый день. Ввожу в курс дела: я пишу игру под android и мне потребовалась в игре небольшая система, которая будет рендерить пул объектов хранящийся в HashMap<Integer, Object>.
Эта мапа заполняется в отдельном потоке. Элементы в мапу добавляются с небольшим промежутком времени(чтобы потом рендерились не все объекты сразу)
Вот код метода run();
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
    public void run() {
        if(!shotdown) {
            for(int i = 0; i < sizeArray; i++) {
                try {
                    Thread.sleep(100);
                    dummies.put(position, new Dummy(BodyFactory.createDummy(world)));
                    position++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        shotdown = !shotdown;
    }
Код тривиален... каждые 100 мс добавляем в мапу объект, который в дальнейшем будет рендериться

Для дальнейшего понимания: Есть некоторый класс Level унаследованный от Thread, соответственно код выше относится к этому классу
Объект класса Level создается в классе отвечающем за игровой мир. Вот код этого класса
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
public class PlayState extends State {
    private float frameCount;
    private World world;
    private Box2DDebugRenderer debugRenderer;
    private OrthographicCamera camera;
    private Level level;
    private SpaceShip spaceShip;
 
    public PlayState(GameStateManager gsm) {
        super(gsm);
        frameCount = 0;
        Constans.WIDTH = Gdx.graphics.getWidth();
        Constans.HEIGHT = Gdx.graphics.getHeight();
 
        world = new World(Constans.GRAVITY, Constans.SLEEP);
        world.setContactListener(new ContactObject());
 
        camera = new OrthographicCamera(Constans.WIDTH / 2, Constans.HEIGHT / 2);
        camera.position.set(new Vector2(100.0f, 100.0f), 0);
 
        debugRenderer = new Box2DDebugRenderer();
 
        level = new Level(world);
        level.start();
        spaceShip = new SpaceShip(BodyFactory.createSpaceShip(world));
    }
 
    @Override
    protected void handleInput() throws InterruptedException {
        if(Gdx.input.getX() >= 0 && Gdx.input.getX() <= 40 && Gdx.input.getY() >= Constans.HEIGHT -45 && Gdx.input.getY() <= Constans.HEIGHT +30) {
            dispose();
            gsm.set(new MenuState(gsm));
        }
 
        if(spaceShip != null) {
            if (Constans.STYLE_CONTROL) {
                spaceShip.tapControl();
            } else {
                spaceShip.AccControl();
            }
        }
    }
 
    @Override
    public void update(float time) throws InterruptedException {
        camera.setToOrtho(false, Constans.WIDTH / 2, Constans.HEIGHT / 2);
        handleInput();
 
        if(spaceShip != null) {
            spaceShip.update(time);
        }
        for (Map.Entry entry : level.getDummies().entrySet()) {
            if(entry != null && entry.getValue() instanceof Dummy) {
                level.checkScreen(entry.getValue(), level.getPosition());
                Dummy dummy = (Dummy) entry.getValue();
                level.setPosition((Integer) entry.getKey());
                dummy.update(time);
            }
        }
    }
 
    @Override
    public void render(SpriteBatch batch) throws InterruptedException {
        world.step(1f, 2, 2);
        debugRenderer.render(world, camera.combined);
        batch.setProjectionMatrix(camera.combined);
        batch.begin();
        frameCount += Gdx.graphics.getDeltaTime();
        batch.draw(Constans.BG_PLAY_SCREEN.getKeyFrame(frameCount, true),0, 0);
 
        if(spaceShip != null) {
            batch.draw(spaceShip.getParameters().getTypeShip(), spaceShip.getPosition().x, spaceShip.getPosition().y);
        }
        for (Map.Entry entry : level.getDummies().entrySet()) {
            if(entry != null && entry.getValue() instanceof Dummy) {
                level.checkScreen(entry.getValue(), level.getPosition());
                Dummy dummy = (Dummy) entry.getValue();
                level.setPosition((Integer) entry.getKey());
                batch.draw(dummy.getParameters().getSkin(), dummy.getPosition().x, dummy.getPosition().y);
            }
        }
 
        batch.draw(Constans.SETTING_PLAY_SCREEN, 0, 0);
        batch.end();
    }
 
    @Override
    public void dispose() {
        if(spaceShip != null) {
            spaceShip.resetParameters();
        }
        if(level != null) {
            level.stop();
            level.dispose();
        }
    }
}
В методе update и render мы пробегаемся по всем объектам нашего пула и вызываем соответствующие методы для обновления и рендеринга каждого объекта.
На словах все вроде бы не сильно сложно. Но по итогам такого алгоритма возникает куча непонятных проблем.
1) Игра крашится, спустя некоторое количество отрисованых объектов
2) Методы update и render у объектов, которые отрисовываются отрабатывают не до конца.
А конкретно выглядит это так: объект отрисовался прошло 100мс(время указанное в методе run) и он исчезает. После отрисовывается другой объект. Почему так происходит? Ведь каждый элемент пула ссылается на разные объекты, а не на один и тот же.
В логах нет никаких вылетов ошибок и прочего. Приложение просто останавливается и все...
Буду благодарен за помощь.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Alexvp
107 / 71 / 8
Регистрация: 03.08.2014
Сообщений: 344
13.05.2016, 09:50     Непонятное поведение многопоточного приложения #2
Конечно, это ваше личное дело. Но зачем изобретать велосипед? Возьмите, например, движок LibGDX, где все эти процессы нижнего уровня хорошо реализованы и протестированы. И сосредоточьтесь на gameplay своей игры.
vxg
Модератор
 Аватар для vxg
2718 / 1729 / 170
Регистрация: 13.01.2012
Сообщений: 6,463
13.05.2016, 10:03     Непонятное поведение многопоточного приложения #3
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от кверти Посмотреть сообщение
Почему так происходит?
вы добавляете в мап объекты в потоке и перебираете этот же мап в другом потоке что бы отрисовать элементы - откуда уверенность в том что мап потокобезопасен и его не расторащит от одновременного перебора и добавления? где Semaphore на худой случай?
кверти
4 / 4 / 1
Регистрация: 22.09.2013
Сообщений: 136
Завершенные тесты: 2
13.05.2016, 12:47  [ТС]     Непонятное поведение многопоточного приложения #4
Спасибо за ответ. А можно узнать какие классы в libGdx позволяют реализовать данный механизм? Дело в том, что я взял за основу этот фреймворк, но, видимо, плохо в нем еще ориентируюсь

Добавлено через 42 секунды
Спасибо, попробую
Паблито
не спать!
1868 / 1602 / 493
Регистрация: 12.05.2014
Сообщений: 5,796
Завершенные тесты: 1
13.05.2016, 14:42     Непонятное поведение многопоточного приложения #5
Сообщение было отмечено автором темы, экспертом или модератором как ответ
http://developer.android.com/intl/ru...ntHashMap.html
https://habrahabr.ru/post/132884/
Alexvp
107 / 71 / 8
Регистрация: 03.08.2014
Сообщений: 344
13.05.2016, 20:20     Непонятное поведение многопоточного приложения #6
Цитата Сообщение от кверти Посмотреть сообщение
А можно узнать какие классы в libGdx позволяют реализовать данный механизм
В сети навалом неплохих уроков по этому движку.
Одно могу сказать, что большое число объектов рендить накладно.
vxg
Модератор
 Аватар для vxg
2718 / 1729 / 170
Регистрация: 13.01.2012
Сообщений: 6,463
14.05.2016, 00:42     Непонятное поведение многопоточного приложения #7
Цитата Сообщение от Alexvp Посмотреть сообщение
Одно могу сказать, что большое число объектов рендить накладно.
позвольте с вами в этом вопросе согласиться и довести мысль до логического завершения - минимальная нагрузка на процессор будет если не рендерить вообще ничего
Alexvp
107 / 71 / 8
Регистрация: 03.08.2014
Сообщений: 344
14.05.2016, 13:23     Непонятное поведение многопоточного приложения #8
Цитата Сообщение от vxg Посмотреть сообщение
минимальная нагрузка на процессор будет если не рендерить вообще ничего
Логично
Уменьшение числа объектов можно делать за счет их группировки, но это зависит от геймплея игры. Однажды мне пришлось часть объектов включать в фоновый рисунок, так как они должны были быть на экране, но не были активными. Таким образом, вместо полутора десятков объектов рендился только один.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.05.2016, 17:24     Непонятное поведение многопоточного приложения
Еще ссылки по теме:

Неадекватное поведение адаптера ListView Android
Android Из приложения А проверить наличие установленного на устройстве приложения В
Непонятное отображение spinner Android
Android Непонятное поведение программы!
Android Sockets и потоки, разное поведение на устройствах

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

Или воспользуйтесь поиском по форуму:
vxg
Модератор
 Аватар для vxg
2718 / 1729 / 170
Регистрация: 13.01.2012
Сообщений: 6,463
14.05.2016, 17:24     Непонятное поведение многопоточного приложения #9
Alexvp, если он рендерился то без разницы сколько вы напихали единиц в группу а если это рисунок то и ежу понятно что нет нужды бить фон на 1000 элементов
Yandex
Объявления
14.05.2016, 17:24     Непонятное поведение многопоточного приложения
Ответ Создать тему
Опции темы

Текущее время: 07:24. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru