views:

2934

answers:

4

I'm developing a game for Android. It's got a lot going on but is running reasonably smoothly. That is, of course, until the user touches the screen.

While they're touching it, onTouchEvent is called (with action = ACTION_MOVE, x = 0 and y = 0) roughly once every ten milliseconds at what appears to be a fairly high priority, as it absolutely obliterates the framerate. As soon as the touch ends the framerate returns to its nice state.

I've tried

  • having onTouchEvent handle input for the game as usual
  • having onTouchEvent return true straight away
  • not having onTouchEvent implemented at all

The problem persists in all three situations.

Has anyone encountered this? Is there a way to reduce the rate at which ACTION_MOVE events are generated, or to ensure that they're only generated when there is actual movement, or use a polling method that just gets the current location of the touch? Or even just a way to disable it entirely?

A: 

Perhaps a somewhat obvious solution, but... have you tried only handling about 1/10 of them? If you're doing processing that's triggered every 10ms on the UI thread, that's likely going to slow down the framerate, yes. So what if you just accumulate a counter somewhat instead and only do any processing once that's gotten past some minimal threshold?

pjz
+9  A: 

Read this thread. Basically you want to sleep the event thread since otherwise the system will pump a lot of events (between x,y and pressure there is always some movement going on) that you need to handle.

hacken
A: 

I've been trying to follow everything you guys have been talking about, but I must admit that after trying several ways of implementing what you suggest, I still haven't been able to achieve any positive results. Could one of you provide some example code? Specifically, I'd like to know how to go about making the main/UI thread sleep. If it's applicable to my games, it would also be nice to know how to set up a polling model like Jon implemented.

Here's what my code looks like. On the UI thread:

public boolean onTouchEvent(MotionEvent event) {
    // Store event somewhere the game thread can see it:
    // ...

    synchronized (someObject) {
        try {
            someObject.wait(1000L);
        } catch (InterruptedException e) {
        }
    }

    return true;
}

and on the Game thread:

void myGame() {
    while (!stopping) {
        // ...

        // Get a touch event:
        synchronized (someObject) {
            someObject.notify();
        }
        Thread.yield();

        // ...
    }
}
Damocles
A: 

Damocles, Just tested with this workaround. It stops the MotionEvent flood the same way sleep(16) does but as far as system CPU utilization goes, it is completely ineffective. My game still drops from 50fps to 25fps on a G1 from touch alone. I'm seeing system_server use 36% of the CPU while touching using this code still. If I let off, it drops down under 5%.

rbgrn