Android:Touch严重降低了我的应用程序速度

时间:2010-12-03 04:27:00

标签: android touch

我一直在这个问题上绞尽脑汁。

当我正在运行我的应用程序(opengl游戏)时,传送很顺利但是当我触摸屏幕时,我的应用程序非常严重地减速(在强大的手机上没有明显的感觉,例如nexus,但是在htc魔术上它变得非常烦人)

我做了一个跟踪,发现触摸事件似乎是在不同的线程中处理的,即使它没有花费那么多的处理时间,我认为orroids在线程之间切换的能力也不是那么好...... / p>

当速度成为问题时,处理触摸的最佳方法是什么?

目前我正在使用: 在GLSurfaceView

@Override
 public boolean onTouchEvent(MotionEvent event) {
     GameHandler.onTouchEvent(event);
     return true;
 }

欢迎任何想法

4 个答案:

答案 0 :(得分:5)

我有一种感觉,下面的错误报告可能是相关的。可悲的是,它似乎只能在姜饼中修复。

Bug report

刚刚看到SO更喜欢答案中的细节,以防链接消失等。上面提到了Adnroid 2.1中谷歌接受的错误,目标是在姜饼发布中修复。

问题7836:system_server消耗过多的CPU处理触摸事件

答案 1 :(得分:2)

我自己也不能担保,但是我的研究表明,触摸屏幕会引发很多事件,导致事件队列充斥,因此CPU会占用你的资源。

尝试放: -

   try {
        Thread.sleep(16);
    } catch (InterruptedException e) {} //ignore

在onTouch方法中的任何返回之前(通常只有最后一个 - 但只是确保)。我知道睡眠通常是一件非常糟糕的事情,但它不在UI线程中,所以应该没问题。睡眠16应该将FPS限制在60。

答案 2 :(得分:1)

不要对onTouchEvent()进行繁重的计算。 OnTouchEvent每个手指每秒可以发射数十或数百次,你应该将繁重的计算推迟到游戏的其他部分(例如物理引擎或图形引擎)。特别要避免在onTouchEvent中绘图。

您最好使用onClickEvent或其他不太密集的鼠标事件,并且只有在真正需要跟踪触摸动作时才使用onTouchEvent。

答案 3 :(得分:0)

@Jason:

这将是一个评论,但它变得太大了,它与我刚才给出的答案不同[更好]。

我已使用此处所述的此方法更改了我的实现 http://obviam.net/index.php/the-android-game-loop/

通过使用上述方法意味着您不需要睡眠OnTouch事件。

另外,请不要忘记保护您的游戏循环线程,如http://wonton-games.blogspot.com/2010/06/lunar-lander-resume-game-workaround.html

所述

另外请记住,Chris Pruett写Replica Island时说他使用了2个线程,一个用于update(),另一个用于render() - 两者都必须受到保护。

克里斯确实以16毫秒(60 fps)的速度睡眠他的OnTouch以减少事件 - 所以如果你仍然需要减少事件,我会说最好去试验 - 你只需触摸屏幕就会发生什么事情发生在看看它是否滞后,从而随后放手时加速。

对于我目前的需求,我使用相同的线程,因为我还没有进入OpenGL,我仍然使用画布。但是当我使用OpenGL时,它将是2个线程,并且每个线程都将是它自己的完整类。

最后,我没有通过计算帧来计算我的精灵,我用计时器包裹它们。我将分享我的课程并告诉你我是如何称呼它的。请记住,我仍然是Java新手,所以对代码不好道歉。

package com.yourname.yourapplication;

//Used for doing something after a set time
public class TimeDo {
    private int mRepeat = 0; //Stores the last wait period for the reset() later
    private long mTime = 0; //The goal time of when its due
    private boolean mFlagged = false; //Stop them getting a second true on a subsequent check

    public TimeDo(int milliseconds) {
        reset(milliseconds);
    }

    public TimeDo() {
        this(0);
    }

    public void reset(int milliseconds) {
        mRepeat = milliseconds;
        mTime = System.currentTimeMillis() + milliseconds;
        mFlagged = mRepeat==0; //ignore if zero
    }

    public void reset() { //Set it back to the delay used last time 
        reset(mRepeat);
    }

    public boolean check() {
        if (mFlagged) //Assert: shouldn't really happen
            return false;
        mFlagged = System.currentTimeMillis() > mTime; 
        return mFlagged;
    }

    public boolean checkAndReset() {
        if (check()) {
            reset();
            return true;
        }
        return false; //note mFlagged could be true here, so don't use it
    }

}

这样实施: -

public class Gem {
    private TimeDo mMoveGem = new TimeDo(100); //move 10 times a second, 100ms 
    private int mX = 0;
    private int mY = 0;
    private int mMoveX = 3;
    private int mMoveY = 4;
    .
    .
    .   
    public void update() {
        if (mMoveGem.checkAndReset()) {
            mX += mMoveX;
            mY += mMoveY;
            .
            .
        }
    }

    public void render(Canvas canvas) {
    //etc etc
        .
        .
    }

}

希望任何有用的东西! 对不起,如果你必须重写你的大量应用程序 - 我做了。

编辑:那个TimeDo类不是postDelayed runnable,就像自动警报一样。如果您不检查,则不会触发“事件”。你可能会兴奋并让它创建一个runnable并传递一个驻留在你的类中的回调方法(想想一个OnClick方法) - 但是无法运行一个更新所有组件的独有的time-able update()线程。