You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跳棋游戏drawPawns代码运行触发ANR弹窗,如何优化消除该问题

问题根因分析

ANR出现的核心原因是当前drawPawns方法存在多余耗时操作,且大概率存在高频重复调用、或执行了大量无效UI渲染的问题:

  • setBackgroundResource每次调用都会重新解码对应drawable资源,全量遍历所有棋盘格子时如果格子数量多、方法被重复调用,累计耗时会快速上涨,阻塞主线程
  • 方法没有做脏校验,每次调用都全量更新所有格子,哪怕大部分格子的棋子状态没有发生变化
  • 如果该方法被放到非UI线程执行,或者主线程同时被其他计算任务阻塞,也会触发ANR

具体优化方案

1. 提前缓存Drawable资源,避免重复解码

不要每次调用setBackgroundResource都让系统重新加载资源,提前在页面/视图初始化阶段就把所有用到的棋子drawable缓存起来:

// 类成员变量,在onCreate/View初始化阶段完成赋值
private Drawable whitePawnDrawable;
private Drawable brownPawnDrawable;
private Drawable whiteQueenDrawable;
private Drawable brownQueenDrawable;
private Drawable emptyDrawable;

// 初始化逻辑,整个页面生命周期只执行一次
private void initDrawables(Context context) {
    whitePawnDrawable = ContextCompat.getDrawable(context, R.drawable.white_pawn);
    brownPawnDrawable = ContextCompat.getDrawable(context, R.drawable.brown_pawn);
    whiteQueenDrawable = ContextCompat.getDrawable(context, R.drawable.white_queen);
    brownQueenDrawable = ContextCompat.getDrawable(context, R.drawable.brown_queen);
    emptyDrawable = new ColorDrawable(Color.TRANSPARENT);
}

之后更新背景时直接用setBackground方法传入缓存好的drawable,跳过资源解码步骤。

2. 增加脏数据校验,只更新状态发生变化的格子

不要每次全量遍历所有格子,维护上一次的棋子状态数组,仅对比更新状态发生变化的格子:

// 类成员变量,存储上一次渲染的棋子状态
private int[] lastPawnState;

public void drawPawns() {
    if (lastPawnState == null) {
        lastPawnState = new int[playableTile.length];
    }
    for(int i=0; i<playableTileView.length; i++) {
        int currentState = playableTile[i].getIsTaken();
        // 状态没有变化直接跳过渲染
        if (currentState == lastPawnState[i]) {
            continue;
        }
        // 状态变化才更新UI,同时记录新状态
        lastPawnState[i] = currentState;
        Drawable targetDrawable;
        switch (currentState) {
            case 1:
                targetDrawable = whitePawnDrawable;
                break;
            case -1:
                targetDrawable = brownPawnDrawable;
                break;
            case 2:
                targetDrawable = whiteQueenDrawable;
                break;
            case -2:
                targetDrawable = brownQueenDrawable;
                break;
            default:
                targetDrawable = emptyDrawable;
                break;
        }
        playableTileView[i].setBackground(targetDrawable);
    }
}

如果是玩家走子、AI走子的常规场景,甚至可以不用遍历整个数组,直接只更新走子涉及到的2-3个格子(起点、落点、被吃的棋子位置),性能提升会更明显。

3. 线程逻辑优化

所有调用drawPawns的逻辑都要放在主线程执行,不要在子线程直接操作UI;如果有其他耗时计算(比如AI走子逻辑、胜负判定逻辑),放到子线程执行,计算完成后再切主线程更新UI。
如果确实需要全量刷新棋盘,不要在动画、手势响应等对时延要求高的场景调用该方法。

内容的提问来源于stack exchange,提问作者Franklyn Oreben

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 01:39:03