2017-08-03 68 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,並將緩存的位圖繪製到屏幕上。