Android:高效准确地反复绘制许多小形状

时间:2017-08-03 03:10:08

标签: android android-canvas android-bitmap ondraw

我正在开发一个Android项目,用于构建Abelian Sandpiles(一种2D元胞自动机)。我有一个单元格网格(从小开始但后来长大)我在网格上绘制正方形(或圆圈)以显示每个单元格的状态。在每一步,我通常更新不到30%的细胞。

我的基本方法来自这篇文章:Android: How to get a custom view to redraw partially?

我将所有形状绘制到画布并将其作为位图缓存,然后在每一步我只更新需要更新的单元格,然后缓存结果并重复。当网格相当小(小于50 x 50)时,这种方法效果很好,但随着网格尺寸的增加,网格变得越来越不令人满意。问题在于

1)当更新次数变高时,它太慢了

2)即使它运行平稳,绘图看起来也不干净 - 例如,一行小矩形看起来很不稳定且不一致(见图)。

choppy artifacts from drawing small rectangles

我确信必须有更好的方法来解决这个问题。使用更大的网格(例如,150 x 150),我绘制宽度为~2.33的圆形或圆形,这不是最佳的。有关提高性能和/或图像质量的建议吗? 简化的绘图代码如下:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (ready) {
            if (needsCompleteRedraw) {
                this.cachedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
                cacheCanvas = new Canvas(this.cachedBitmap);
                doInitialDrawing(cacheCanvas);
                canvas.drawBitmap(this.cachedBitmap, 0, 0, null);
                needsCompleteRedraw = false;
            } else {
                canvas.drawBitmap(this.cachedBitmap, 0, 0, null);
                doPartialRedraws(cacheCanvas);
            }
        }
    }

    private void doInitialDrawing(Canvas clean) {
        for (int i = 0; i < pile.gridHeight; i++) {
            for (int j = 0; j < pile.gridWidth; j++) {
                int state = pile.getGridValueAtPoint(new Point(j, i ));
                clean.drawRect(j * cellSize, i * cellSize, (j + 1 )* cellSize, (i + 1) * cellSize, paints[state]);
            }
        }
    }

    private void doPartialRedraws(Canvas cached) {
        for (Point p : pile.needsUpdateSet) {
            int state = pile.getGridValueAtPoint(p);
            cached.drawRect(p.x * cellSize, p.y * cellSize, (p.x + 1 )* cellSize, (p.y + 1) * cellSize, paints[state]);
        }
        pile.needsUpdateSet = new HashSet<Point>();
    }

我的paint对象设置为antialias为true,我尝试将样式设置为FILL和FILL_AND_STROKE。

我们非常感谢任何建议。

1 个答案:

答案 0 :(得分:0)

确定。这里有几个问题。

1)不要在onDraw中创建画布。如果您认为需要,则无法正确构建绘图代码。

2)绘制缓存位图的要点不是在onDraw中绘制缓存,而是在自己的线程上绘制 - 或者至少在绘制时不这样做。

您应该有第二个线程根据需要绘制到缓存的位图,然后在视图上调用postInvalidate()。 onDraw函数应该只是对drawBitmap的调用,将缓存的位图绘制到屏幕上。