You need to enable JavaScript to run this app. Android Java应用最小化/切后台时崩溃 报IllegalStateException异常
优惠活动
大模型
产品
解决方案
定价
更多

Android Java应用最小化/切后台时崩溃 报IllegalStateException异常

崩溃根因定位

你遇到的崩溃是Surface生命周期与游戏循环线程完全不同步导致的,触发链路和最小化应用的场景完全匹配:

  1. 应用切到后台时,系统会立即触发surfaceDestroyed回调销毁当前Surface
  2. 你在GameView的实现里,把surfaceDestroyed中停止游戏线程的逻辑整个注释掉了,没有修改循环的running标记位,导致游戏循环线程还在后台持续运行
  3. 此时线程执行到lockHardwareCanvas()时,因为Surface已经失效,该方法会直接返回null
  4. 你在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.29 10:36:04