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

自定义键盘实现onDraw方法后耗电与内存占用过高问题求助

自定义KeyboardView onDraw导致高电池消耗与内存占用问题排查与优化

我看了你的代码,能明显发现几个导致性能问题的关键点,咱们一步步来拆解和优化:

原问题代码片段

@Override public void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    healA = ddKeys_Master.autohealing; 
    phealA = ddKeys_Master.autophealing; 
    Paint paint = new Paint(); 
    paint.setTextAlign(Paint.Align.CENTER); 
    //get all your keys and draw whatever you want 
    List<Keyboard.Key> keys = getKeyboard().getKeys(); 
    for (Keyboard.Key key : keys) { 
        if (key.label != null) { 
            paint.setColor(Color.parseColor("#66cccc")); 
            switch (key.codes[0]) { 
                case 888: 
                    if (healA && phealA) { 
                        if (ddKeys_Master.healcount >= ddKeys_Master.autoHealCount) { 
                            paint.setColor(Color.parseColor("#ef0404")); //red 
                            canvas.drawCircle(17 * scale, 17 * scale, 7 * scale, paint); 
                        } else if (ddKeys_Master.healcount >= (ddKeys_Master.autoHealCount * 3 / 4)) { 
                            paint.setColor(Color.parseColor("#ef6904")); //orange 
                            canvas.drawCircle(17 * scale, 17 * scale, 7 * scale, paint); 
                        } 
                        // ... 剩余重复的颜色判断与绘制逻辑
                    } else if (healA) {
                        // ... 重复的healcount判断逻辑
                    } else if (phealA) {
                        // ... 重复的phealcount判断逻辑
                    }
            }
        }
    }
}

核心性能问题分析

  • 频繁创建Paint对象:每次onDraw都会new一个Paint,而onDraw可能每秒被调用几十次,这会产生大量临时对象,频繁触发GC,直接拉高内存占用和CPU消耗,进而增加电池消耗。
  • 重复解析颜色字符串:Color.parseColor()是一个开销不小的操作,你每次绘制都重复解析相同的十六进制颜色,完全是没必要的计算浪费。
  • 冗余的绘制逻辑:大量重复的if-else判断和drawCircle调用,没有做代码复用,增加了CPU的计算量,延长了onDraw的执行时间。
  • 无节制的重绘触发:如果你的逻辑中没有控制invalidate()的调用时机,比如数据没变化也频繁触发重绘,会让onDraw一直重复执行,加剧性能问题。

优化后的代码示例

// 把Paint和颜色常量定义为类成员变量,只初始化一次
private Paint circlePaint;
private final int COLOR_RED = Color.parseColor("#ef0404");
private final int COLOR_ORANGE = Color.parseColor("#ef6904");
private final int COLOR_YELLOW = Color.parseColor("#efeb04");
private final int COLOR_LIGHT_GREEN = Color.parseColor("#09f247");
private final int COLOR_GREEN = Color.parseColor("#17a55e");
private final int COLOR_DEFAULT = Color.parseColor("#66cccc");

// 在构造方法或者onInitialize中初始化Paint
@Override
public void onInitialize() {
    super.onInitialize();
    circlePaint = new Paint();
    circlePaint.setTextAlign(Paint.Align.CENTER);
    circlePaint.setAntiAlias(true); // 开启抗锯齿,提升绘制效果同时不增加太多开销
}

@Override public void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    healA = ddKeys_Master.autohealing; 
    phealA = ddKeys_Master.autophealing; 
    List<Keyboard.Key> keys = getKeyboard().getKeys(); 
    for (Keyboard.Key key : keys) { 
        if (key.label != null && key.codes[0] == 888) { // 只处理目标key,减少循环内判断
            // 复用颜色判断逻辑
            if (healA) {
                drawHealCircle(canvas, 17 * scale, 17 * scale, 7 * scale);
            }
            if (phealA) {
                drawPhealCircle(canvas, 37 * scale, 17 * scale, 7 * scale);
            }
        }
    }
}

// 提取重复的颜色判断逻辑为单独方法
private void drawHealCircle(Canvas canvas, float x, float y, float radius) {
    int color;
    if (ddKeys_Master.healcount >= ddKeys_Master.autoHealCount) {
        color = COLOR_RED;
    } else if (ddKeys_Master.healcount >= (ddKeys_Master.autoHealCount * 3 / 4)) {
        color = COLOR_ORANGE;
    } else if (ddKeys_Master.healcount >= (ddKeys_Master.autoHealCount / 2)) {
        color = COLOR_YELLOW;
    } else if (ddKeys_Master.healcount >= (ddKeys_Master.autoHealCount / 4)) {
        color = COLOR_LIGHT_GREEN;
    } else {
        color = COLOR_GREEN;
    }
    circlePaint.setColor(color);
    canvas.drawCircle(x, y, radius, circlePaint);
}

private void drawPhealCircle(Canvas canvas, float x, float y, float radius) {
    int color;
    if (ddKeys_Master.phealcount >= ddKeys_Master.autoPhealCount) {
        color = COLOR_RED;
    } else if (ddKeys_Master.phealcount >= (ddKeys_Master.autoPhealCount * 3 / 4)) {
        color = COLOR_ORANGE;
    } else if (ddKeys_Master.phealcount >= (ddKeys_Master.autoPhealCount / 2)) {
        color = COLOR_YELLOW;
    } else if (ddKeys_Master.phealcount >= (ddKeys_Master.autoPhealCount / 4)) {
        color = COLOR_LIGHT_GREEN;
    } else {
        color = COLOR_GREEN;
    }
    circlePaint.setColor(color);
    canvas.drawCircle(x, y, radius, circlePaint);
}

额外优化建议

  • 控制重绘时机:只有当healcount、phealcount、healA、phealA这些数据发生变化时,才调用invalidate()触发重绘,避免无意义的重复绘制。
  • 减少不必要的变量读取:如果ddKeys_Master中的字段是频繁读取的,可以考虑在数据变化时缓存到本地成员变量,减少跨对象访问的开销。
  • 开启硬件加速:确保你的View开启了硬件加速(默认是开启的),可以提升Canvas绘制的性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:40:28