Android: touch events block game loop

My code adds touch delegate like this:

pDirector->getTouchDispatcher()->addStandardDelegate(this, 0);

This works fine on iOS. But on Android devices I found that the scene does not update until all touch events are processed. So if I continuously move finger around then it will never update, even if I call refreshDisplay() after each move event. I am testing on a recent ASUS tablet. So it should not be due to slow hardware since the same code is fast enough on iPhone 4. Has anyone seen this issue before?

Very strange — I have not seen this at all with Cocos2d-x 2.2

I have never heard of refreshDisplay() … so maybe this is a 3.0 alpha issue?

Sorry I forgot refreshDisplay() is my own function. It has only one line:

CCDirector::sharedDirector()->drawScene();

I am using cocos2d-x 2.2. I traced into code, and looks like it draws immediately, not deferring to next loop. But I don’t understand why it works only on iOS.

Not sure if it’s related, but I noticed that on iOS everything runs in main thread. On Android, all display and touch event related code runs in a separate game loop thread.

I do not have any calls to drawScene in my game.

Could you post more of your code? I.e. the ccTouchBegan/Moved/Ended functions. On what object do you add the delegate?

A bit of background information. My app is not a game, it’s a photo processing app. When user touches on the picture, I draw circles/lines to a CCRenderTexture, then . The drawing is CPU intensive on large pictures, so I drop the frame rate to low number, and call drawScene() after each touch move event. Thanks for looking into this issue, I appreciate it.

The delegate is on my derived CCScene object:

class PMBlenderScene: public CCScene, public CCTouchDelegate;

void PMBlenderScene::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent)
{
    _brush.rotation = _deviceOrientation.getDeviceOrientation();

    // Keep a list of all active touches to support multi-touch gestures (zoom, rotate etc.)
    for (CCSetIterator iterator = pTouches->begin(); iterator != pTouches->end(); ++ iterator) {
        if (*iterator) {
            CCTouch * touch = static_cast(*iterator);
            _activeTouches.insert(touch);
        }
    }

    updateTouchState();
}

void PMBlenderScene::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
{
    for (CCSetIterator iterator = pTouches->begin(); iterator != pTouches->end(); ++ iterator) {
        if (*iterator) {
            CCTouch * touch = static_cast(*iterator);
            _activeTouches.erase(touch);
        }
    }

    updateTouchState();
}

void PMBlenderScene::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent)
{
        // Removed a few lines of multi touch handling code that's not called in this scenario.
        CCTouch * touch = *_activeTouches.begin();
        CCPoint location = touch->getLocation();

        showCursor(location);

        if (location.x != _previousTouchLocation.x || location.y != _previousTouchLocation.y) {
            // this _renderTexture was used to initialize a CCSprite which is a child node in this scene.
            _brush.drawLineOnRenderTexture(_renderTexture,
                                           convertToRenderContextSpace(_previousTouchLocation),
                                           convertToRenderContextSpace(location));

            _previousTouchLocation = location;
        }
        refreshDisplay();
    }
}

void PMBlenderScene::refreshDisplay()
{
    CCDirector::sharedDirector()->drawScene();
}