我有一个非常简单的游戏SurfaceVIEw,有时游戏几秒钟内没有响应触摸事件,然后它立即响应所有这些触摸事件.我已经在galaxy S3和Nexus 4上测试了我的游戏,它工作正常,似乎这个问题只发生在galaxy S5上.
>主要活动:
public class DroIDzActivity extends Activity {/** Called when the activity is first created. */private static final String TAG = DroIDzActivity.class.getSimplename();@OverrIDepublic 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");}@OverrIDeprotected voID onDestroy() { Log.d(TAG, "Destroying..."); super.onDestroy();}@OverrIDeprotected voID onStop() { Log.d(TAG, "StopPing..."); super.onStop();} }
> MainGamePanel
公共类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);}@OverrIDepublic voID surfaceChanged(SurfaceHolder holder, int format, int wIDth, int height) {}@OverrIDepublic voID surfaceCreated(SurfaceHolder holder) { // at this point the surface is created and // we can safely start the game loop thread.setRunning(true); thread.start();}@OverrIDepublic 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]);}@OverrIDepublic 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;}
> MainThread
公共类MainThread扩展Thread {
private static final String TAG = MainThread.class.getSimplename();// Surface holder that can access the physical surfaceprivate SurfaceHolder surfaceHolder;// The actual vIEw that handles inputs// and draws to the surfaceprivate 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 fpsprivate final static int MAX_FPS = 50; // maximum number of frames to be skippedprivate final static int MAX_FRAME_SKIPS = 5; // the frame periodprivate final static int FRAME_PERIOD = 1000 / MAX_FPS; @OverrIDepublic 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 }}
}
这是应用程序最简单的版本,我已经尝试过,我可以再次重现同样的问题.它还有时需要5到10秒才能在S5上加载,而在Nexus 4和S3上加载的时间不到1秒.
解决方法:
看起来MainThread正在使UI线程挨饿.
最终执行的代码(删除了大量内容)如下所示:
canvas = this.surfaceHolder.lockCanvas();// Do a ton of stuffsurfaceHolder.unlockCanvasAndPost(canvas);canvas = this.surfaceHolder.lockCanvas();// Do a ton of stuffsurfaceHolder.unlockCanvasAndPost(canvas);canvas = this.surfaceHolder.lockCanvas();// Do a ton of stuffsurfaceHolder.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没有指定公平性,因此它应该使用默认值,这可能导致这种饥饿.
尝试移动您的一些工作,特别是锁定/解锁呼叫之外的睡眠.
总结以上是内存溢出为你收集整理的android – 为什么SurfaceView的onTouchEvent被叫几秒延迟?全部内容,希望文章能够帮你解决android – 为什么SurfaceView的onTouchEvent被叫几秒延迟?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)