2017-08-03 27 views
0

我正在开发一个建立Abelian Sandpiles(一种2D细胞自动机)的Android项目。我有一个网格单元格(从小开始,但后来增长),并在网格上绘制正方形(或圆形)以显示每个单元格的状态。在每一步中,我通常更新不到30%的细胞。Android:反复绘制许多小形状,高效且准确

我的基本做法是从这个帖子采取:Android: How to get a custom view to redraw partially?

我画的所有图形到画布上,并将它缓存为位图,然后在每一步我只更新需要更新的细胞,然后缓存结果并重复。当电网相当小(小于50×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>(); 
    } 

和我的油漆对象设置与抗锯齿为真实的,我已经试过样式设置为两个FILL和FILL_AND_STROKE。

任何建议将不胜感激。

+0

屏幕上的细胞越多,越接近编写游戏(在线搜索各种资源)。或者,您可能想看看其他开源游戏生活类型项目如何处理屏幕性能。 –

+0

您也可以参考Android文档(开发 - API指南 - 动画和图形 - 可绘制和可绘制),并使用您使用单独线程绘制的SurfaceView。这非常高效,我相信它可以解决您的问题。 – Zelig63

回答

0

好的。这里有几个问题。

1)不要在onDraw中创建画布。如果您认为需要,您还没有正确构建您的绘图代码。

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

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