Android启动GameActivity崩溃 SurfaceHolder空指针异常排查
问题结论
该崩溃存在明确诱因,属于代码编写错误导致的空指针异常,AndroidManifest配置无问题,不存在Activity未注册的配置错误。
崩溃根因
Logcat明确报错:
崩溃发生在Timer-0子线程,抛出
java.lang.NullPointerException:尝试在空对象引用上调用SurfaceHolder.lockCanvas()方法,对应GameActivity.java第290行绘制逻辑。
核心错误是SurfaceHolder实例从未被正确初始化:surfaceCreated生命周期回调会返回可用的SurfaceHolder实例,但代码中错误地将初始值为null的成员变量surfaceHolder赋值给自身,完全没有使用回调传入的有效实例,导致后续绘制时调用lockCanvas()直接触发空指针。
具体代码问题明细
- 核心赋值错误:
surfaceCreated方法参数传入的有效SurfaceHolder未被使用,错误自赋值导致成员变量始终为null,错误代码片段:
@Override public void surfaceCreated(@NonNull SurfaceHolder holder) { // 错误写法:holder参数未使用,将null值的成员变量赋值给自己 this.surfaceHolder = surfaceHolder; init(); }
- 生命周期绑定缺失:
Timer启动的子线程绘制任务没有和SurfaceView生命周期绑定,后续如果出现Surface销毁(退后台、横竖屏切换),定时任务仍在运行会触发同类空指针崩溃。 - 参数逻辑错误:定时任务的周期参数计算为
1000 - snakeMovingSpeed,当前snakeMovingSpeed定义为800,实际执行周期为200ms,和代码注释标注的800ms移动速度不符,蛇移动速度会比预期快4倍。 - 绘制逻辑无兜底:调用
lockCanvas()和绘制过程没有加非空校验,极端场景下容易出现崩溃。
修复方案
- 修正
surfaceCreated的赋值逻辑,使用回调传入的有效实例:
@Override public void surfaceCreated(@NonNull SurfaceHolder holder) { // 正确赋值:使用回调返回的有效SurfaceHolder this.surfaceHolder = holder; init(); }
- 在
surfaceDestroyed回调中终止定时任务,绑定生命周期:
@Override public void surfaceDestroyed(@NonNull SurfaceHolder holder) { if (timer != null) { timer.purge(); timer.cancel(); timer = null; } canvas = null; }
- 修正移动速度参数,匹配定义的蛇移动速度:
// 将原scheduleAtFixedRate的延迟、周期参数修正 }, 0, snakeMovingSpeed);
- 给绘制逻辑增加非空校验和异常兜底,避免极端场景崩溃:
else { // 非空校验 if (surfaceHolder == null) return; canvas = surfaceHolder.lockCanvas(); if (canvas == null) return; try { // 原有绘制逻辑 canvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR); canvas.drawCircle(snakePointsList.get(0).getPositionX(), snakePointsList.get(0).getPositionY(), pointSize, createPointColor()); canvas.drawCircle(positionX, positionY, pointSize, createPointColor()); for (int i = 1; i < snakePointsList.size(); i++){ int getTempPositionX = snakePointsList.get(i).getPositionX(); int getTempPositionY = snakePointsList.get(i).getPositionY(); snakePointsList.get(i).setPositionX(headPositionX); snakePointsList.get(i).setPositionY(headPositionY); canvas.drawCircle(snakePointsList.get(i).getPositionX(), snakePointsList.get(i).getPositionY(), pointSize, createPointColor()); headPositionX = getTempPositionX; headPositionY = getTempPositionY; } } finally { // 确保canvas正常释放 surfaceHolder.unlockCanvasAndPost(canvas); } }
内容的提问来源于stack exchange,提问作者Bishop
相关产品推荐
相关产品推荐

