Android Java应用最小化/切后台时崩溃 报IllegalStateException异常
崩溃根因定位
你遇到的崩溃是Surface生命周期与游戏循环线程完全不同步导致的,触发链路和最小化应用的场景完全匹配:
- 应用切到后台时,系统会立即触发
surfaceDestroyed回调销毁当前Surface - 你在GameView的实现里,把
surfaceDestroyed中停止游戏线程的逻辑整个注释掉了,没有修改循环的running标记位,导致游戏循环线程还在后台持续运行 - 此时线程执行到
lockHardwareCanvas()时,因为Surface已经失效,该方法会直接返回null - 你在finally代码块里没有对Canvas做判空保护,直接拿着无效的引用调用
unlockCanvasAndPost(c),此时系统底层根本不存在有效的录制锁定状态,就抛出了你日志里看到的IllegalStateException: No recording in progress异常
现有代码的其他逻辑问题
- 存在两个签名完全一致的
surfaceChanged方法,Java语言层面根本不允许类中存在重复签名的方法,说明现有代码是多段代码拼凑的,本身就存在编译级别的隐患 - 游戏循环每17ms就调用一次
holder.setFixedSize(1080,1920),这个方法本身会触发Surface的销毁、重建流程,和循环里的锁Canvas操作跨线程执行,会频繁触发竞态条件 - 线程启动逻辑混乱:代码里同时出现了两套不同的
SurfaceHolder.Callback实现,依靠永久hasStarted标记位控制线程启动,哪怕后续Surface重新创建,也不会正确重启线程,同时还可能出现多次重复启动循环线程的问题 - 循环逻辑没有做Surface有效性校验,不管Surface是否存在都盲目执行锁Canvas、解锁的操作
针对性修复方案
- 恢复
surfaceDestroyed中的线程停止逻辑,确保Surface销毁时立刻终止循环:@Override public void surfaceDestroyed(SurfaceHolder holder) { gameThread.setRunning(false); try { gameThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } - 修改循环的finally块,增加Canvas判空保护,避免无效的解锁调用:
finally { // 仅当Canvas是有效锁定状态时才执行解锁 if (c != null) { view.getHolder().unlockCanvasAndPost(c); } } - 把每帧执行的
setFixedSize逻辑移到surfaceChanged回调里执行一次,不要放在游戏循环中反复调用,避免触发不必要的Surface重建 - 删除重复定义的
surfaceChanged方法,仅保留一个符合SurfaceHolder.Callback接口规范的实现,消除编译隐患 - 调整线程启动逻辑:在
surfaceCreated回调中先判断线程运行状态,仅当线程未运行时才设置running=true并启动线程,避免重复启动多个循环
补充:日志中
No recording in progress的报错本质是解锁操作没有对应的锁定前置操作,只要把Surface生命周期和线程执行逻辑做同步,配合判空保护就能彻底消除这类崩溃。
内容的提问来源于stack exchange,提问作者FiveJungYetNoSmite
相关产品推荐
相关产品推荐

