优化Android自定义View代码,使Profiler内存图表平滑
问题分析与优化方案
内存陡增+频繁GC的根源
- 无限循环重绘:自定义View的
draw()方法中调用invalidate(),导致View持续触发重绘(每秒约60次),characterCreator.draw()被高频执行。 - Bitmap重复创建且未回收:每次调用
characterCreator.draw()时,都会通过Bitmap.createScaledBitmap()生成新的Bitmap对象,旧的imageResizedBitmap未被回收,大量内存被重复占用,进而触发频繁GC。
具体优化步骤
1. 终止无限重绘
移除CharacterCreatorView.draw()中的invalidate()调用,改用可控的动画逻辑触发重绘:
- 如果是帧动画场景,用
Handler或ValueAnimator控制重绘间隔(比如每秒24/30帧),避免无意义的高频刷新。
修改后的CharacterCreatorView.java示例:
@Override public void draw(Canvas canvas) { super.draw(canvas); if(characterCreator != null) characterCreator.draw(canvas); } // 用Handler控制动画帧更新节奏 private final Handler animationHandler = new Handler(Looper.getMainLooper()); private final Runnable animationRunnable = new Runnable() { @Override public void run() { // 这里写切换动画帧的逻辑(比如更新colUsing) characterCreator.updateFrame(); invalidate(); animationHandler.postDelayed(this, 1000/30); // 30帧每秒 } }; // 启动动画 public void startAnimation() { animationHandler.post(animationRunnable); } // 停止动画 public void stopAnimation() { animationHandler.removeCallbacks(animationRunnable); }
2. 提前预缩放Bitmap,避免重复创建
不在draw()方法中创建Bitmap,而是在初始化或切换动画帧/方向时完成缩放,并及时回收旧Bitmap:
修改CharacterCreator.java示例:
// 直接绘制预缩放好的Bitmap,不再在draw里创建新对象 public void draw(Canvas canvas) { canvas.drawBitmap(imageResized, 0, 0, null); } // 切换帧时调用,负责更新缩放后的Bitmap并回收旧对象 public void updateFrame() { Bitmap currentBitmap = getCurrentMoveBitmap(); if (currentBitmap != null && !currentBitmap.equals(imageResized)) { // 回收旧Bitmap释放内存 if (imageResized != null && !imageResized.isRecycled()) { imageResized.recycle(); } // 缩放新帧的Bitmap imageResized = Bitmap.createScaledBitmap(currentBitmap, 300, 300, false); } } // 初始化时预加载第一帧的缩放Bitmap public CharacterCreator(Bitmap baseSprite) { this.image = baseSprite; this.widthAllCols = image.getWidth(); this.heightAllRows = image.getHeight(); this.widthOneFrame = this.widthAllCols / 13; this.heightOneFrame = this.heightAllRows / ROW_COUNT; this.topToBottoms = new Bitmap[COL_COUNT]; this.rightToLefts = new Bitmap[COL_COUNT]; this.leftToRights = new Bitmap[COL_COUNT]; this.bottomToTops = new Bitmap[COL_COUNT]; // 初始化第一帧的缩放对象 Bitmap firstBitmap = getMoveBitmaps()[0]; imageResized = Bitmap.createScaledBitmap(firstBitmap, 300, 300, false); }
3. 补充:Bitmap全生命周期内存管理
当CharacterCreator不再被使用时,主动回收所有Bitmap资源,避免内存泄漏:
public void release() { recycleBitmapArray(leftToRights); recycleBitmapArray(rightToLefts); recycleBitmapArray(topToBottoms); recycleBitmapArray(bottomToTops); if (imageResized != null && !imageResized.isRecycled()) { imageResized.recycle(); } if (image != null && !image.isRecycled()) { image.recycle(); } } private void recycleBitmapArray(Bitmap[] bitmaps) { if (bitmaps == null) return; for (Bitmap bmp : bitmaps) { if (bmp != null && !bmp.isRecycled()) { bmp.recycle(); } } }
内容的提问来源于stack exchange,提问作者user19516326
相关产品推荐
相关产品推荐

