gpt4 book ai didi

android - 为什么SurfaceView的onTouchEvent调用会延迟几秒?

转载 作者:太空宇宙 更新时间:2023-11-03 12:53:08 25 4
gpt4 key购买 nike

我有一个非常简单的 SurfaceView 游戏,有时游戏会在几秒钟内不响应触摸事件,然后它会立即响应所有这些触摸事件。我已经在 Galaxy S3 和 Nexus 4 上测试了我的游戏,它运行良好,似乎这个问题只出现在 Galaxy S5 上。

  1. 主要 Activity :

    public class DroidzActivity extends Activity {
    /** Called when the activity is first created. */

    private static final String TAG = DroidzActivity.class.getSimpleName();

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // requesting to turn the title OFF
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    // making it full screen
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    // set our MainGamePanel as the View
    setContentView(new MainGamePanel(this));
    Log.d(TAG, "View added");
    }

    @Override
    protected void onDestroy() {
    Log.d(TAG, "Destroying...");
    super.onDestroy();
    }

    @Override
    protected void onStop() {
    Log.d(TAG, "Stopping...");
    super.onStop();
    }

    }
    1. 主游戏面板

公共(public)类 MainGamePanel 扩展 SurfaceView 实现 SurfaceHolder.Callback {

private static final String TAG = MainGamePanel.class.getSimpleName();

private MainThread thread;

public MainGamePanel(Context context) {
super(context);
// adding the callback (this) to the surface holder to intercept events
getHolder().addCallback(this);

// create the game loop thread
thread = new MainThread(getHolder(), this);

// make the GamePanel focusable so it can handle events
setFocusable(true);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// at this point the surface is created and
// we can safely start the game loop
thread.setRunning(true);
thread.start();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "Surface is being destroyed");
// tell the thread to shut down and wait for it to finish
// this is a clean shutdown
boolean retry = true;
while (retry) {
try {
thread.setRunning(false);
thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
Log.d(TAG, "Thread was shut down cleanly");
}

public void render(Canvas canvas){
if(canvas!=null)
canvas.drawColor(colorList[colorIndex]);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
colorIndex++;
colorIndex = colorIndex % colorList.length;
}

return super.onTouchEvent(event);
}
int [] colorList = {Color.RED, Color.GREEN, Color.BLUE, Color.GRAY};
int colorIndex = 0;

}
  1. 主线程

    公共(public)类 MainThread 扩展线程 {

    private static final String TAG = MainThread.class.getSimpleName();

    // Surface holder that can access the physical surface
    private SurfaceHolder surfaceHolder;
    // The actual view that handles inputs
    // and draws to the surface
    private MainGamePanel gamePanel;

    // flag to hold game state
    private boolean running;
    public void setRunning(boolean running) {
    this.running = running;
    }

    public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
    super();
    this.surfaceHolder = surfaceHolder;
    this.gamePanel = gamePanel;
    }


    // desired fps
    private final static int MAX_FPS = 50;
    // maximum number of frames to be skipped
    private final static int MAX_FRAME_SKIPS = 5;
    // the frame period
    private final static int FRAME_PERIOD = 1000 / MAX_FPS;


    @Override
    public void run() {
    Canvas canvas;
    Log.d(TAG, "Starting game loop");

    long beginTime; // the time when the cycle begun
    long timeDiff; // the time it took for the cycle to execute
    int sleepTime; // ms to sleep (<0 if we're behind)
    int framesSkipped; // number of frames being skipped

    sleepTime = 0;

    while (running) {
    canvas = null;
    // try locking the canvas for exclusive pixel editing
    // in the surface
    try {
    canvas = this.surfaceHolder.lockCanvas();
    synchronized (surfaceHolder) {
    beginTime = System.currentTimeMillis();
    framesSkipped = 0; // resetting the frames skipped
    // update game state
    // this.gamePanel.update();
    // render state to the screen
    // draws the canvas on the panel
    this.gamePanel.render(canvas);
    // calculate how long did the cycle take
    timeDiff = System.currentTimeMillis() - beginTime;
    // calculate sleep time
    sleepTime = (int)(FRAME_PERIOD - timeDiff);

    if (sleepTime > 0) {
    // if sleepTime > 0 we're OK
    try {
    // send the thread to sleep for a short period
    // very useful for battery saving
    Thread.sleep(sleepTime);
    } catch (InterruptedException e) {}
    }

    while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
    // we need to catch up
    // update without rendering
    // this.gamePanel.update();
    // add frame period to check if in next frame
    sleepTime += FRAME_PERIOD;
    framesSkipped++;
    }
    }
    } finally {
    // in case of an exception the surface is not left in
    // an inconsistent state
    if (canvas != null) {
    surfaceHolder.unlockCanvasAndPost(canvas);
    }
    } // end finally
    }
    }

这是最简单的应用程序版本,我已经尝试过并且能够再次重现同样的问题。有时在 S5 上加载需要 5-10 秒,而在 Nexus 4 和 S3 上加载不到 1 秒。

最佳答案

看起来 MainThread 正在使 UI 线程处于饥饿状态。

最终执行的代码(删除了很​​多东西)如下所示:

canvas = this.surfaceHolder.lockCanvas();
// Do a ton of stuff
surfaceHolder.unlockCanvasAndPost(canvas);
canvas = this.surfaceHolder.lockCanvas();
// Do a ton of stuff
surfaceHolder.unlockCanvasAndPost(canvas);
canvas = this.surfaceHolder.lockCanvas();
// Do a ton of stuff
surfaceHolder.unlockCanvasAndPost(canvas);

这是android源码支持的。请注意 SurfaceHolder#lock 调用 mSurfaceLock.lock() .这也称为 SurfaceHolder#updateWindow ,在该文件的许多其他地方被调用。

mSurfaceLock 是一个 ReentrantLock ,文档说明:

The constructor for this class accepts an optional fairness parameter. When set true, under contention, locks favor granting access to the longest-waiting thread. Otherwise this lock does not guarantee any particular access order.

SurfaceView 没有指定公平性,所以它应该使用默认值,这可能会导致这种饥饿。

尝试转移一些工作,尤其是在锁定/解锁调用之外的 sleep 时间。

关于android - 为什么SurfaceView的onTouchEvent调用会延迟几秒?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26391770/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com