2016-06-09 68 views
2

我一直在嘗試儘可能多地從SurfaceView中擠出性能。目前,我將它繼承並實現了一個可運行的接口,而不是回調。我知道它沒有硬件加速。不過,如果我畫一個畫布原始垂直線在屏幕上或者垂直線上滾動,那麼在每次傳遞之後,它們都會運行得越慢越慢。這讓我感覺像內存泄漏,還是僅僅是Android本身? OpenGL或其他庫真的是我的最後一招?SurfaceView垂直線繪製在屏幕上速度太慢

我已經繪製了大量的滾動背景之前在體面的速度(我認爲每個蜱周圍5個像素,這是我瞄準20-50像素左右的勾號,如果有什麼東西會減少停止沿呈現的方式) 。

編輯:這裏是SurfaceView擴展,線程,繪製方法和初始化。基本上,這是一個稍微大一點的類,只是擁有這個屏幕的數據。 drawXYZ()方法只是簡單地使用畫布基元或位圖來主要作爲背景進行繪製,這是一種純色的背景色,其上有一些垂直和水平的線條,就像音樂人員一樣,只涉及少量計算。

drawCursor是什麼讓滾動垂直線,當我只是讓它循環滾動從左到右,它最終落後得比第一次滾動慢得多。

public class MySurfaceView extends SurfaceView implements Runnable 
{ 
    Thread renderThread = null; 
    SurfaceHolder holder; 
    volatile boolean running = false; 

    public MySurfaceView() { 
     super(mainActivity); 
     this.holder = getHolder(); 
     holder.setFixedSize(screenW, screenH); 
    } 

    public void resume() { 
     running = true; 
     renderThread = new Thread(this); 
     renderThread.start(); 
    } 

    @Override 
    public void run() { 
     while (running) { 
      if (!holder.getSurface().isValid()) { 
       continue; 
      } 

      Canvas canvas = holder.lockCanvas(); 
      if(canvas != null) { 
       doDraw(canvas); 
       holder.unlockCanvasAndPost(canvas); 
      } 
     } 
    } 

    public void pause() { 
     running = false; 
     while (true) { 
      try { 
       renderThread.join(); 
       break; 
      } catch (InterruptedException e) { 
       // retry 
      } 

     } 
    } 

    protected void doDraw(Canvas canvas) 
    { 
     canvas.drawColor(Color.rgb(56, 56, 62)); 

     lastNotePlayed = OptionsContainer.getNotePlaying(); 

     //Draw contours (rows). 
     paint.setColor(Color.rgb(0, 255, 255)); 
     paint.setStrokeWidth(3); 
     paint.setTextSize(35); 
     drawContours(canvas, paint); 

     //Beats per measure (BPM). 
     paint.setColor(Color.rgb(233, 232, 232)); 
     paint.setStrokeWidth(1); 
     paint.setStyle(Paint.Style.STROKE); 
     paint.setPathEffect(bpmLines); 
     drawBPM(canvas, paint); 
     paint.setPathEffect(null); 

     //Draw measures. 
     paint.setStrokeWidth(5); 
     drawMeasures(canvas, paint); 

     //Draw note node inputs. 
     paint.setColor(Color.rgb(76, 255, 0)); 
     for (int i = 0; i < OptionsContainer.noteList.length; i++) { 
      if (OptionsContainer.noteList[i].getContour() != 0) { 
       if (OptionsContainer.noteList[i].getContour() > (OptionsContainer.contour/2)) { 
        //Staff on left side, below note. 
        canvas.drawBitmap(lowerStaffBmp, OptionsContainer.noteList[i].getX(), OptionsContainer.noteList[i].getY(), null); 
       } else { 
        canvas.drawBitmap(higherStaffBmp, OptionsContainer.noteList[i].getX(), OptionsContainer.noteList[i].getY() - 40, null); 
       } 
      } 
     } 

     //Draw cursor. 
     paint.setStrokeWidth(2); 
     paint.setColor(Color.WHITE); 
     drawCursor(canvas, paint); 

     if (OptionsContainer.isRest) 
      canvas.drawBitmap(restBmp, (OptionsContainer.screenWidth/2), (screenHeight - 100)/2, null); 
    } 
} 

@Override 
public void init() { 
    surfaceView = new MySurfaceView(); 
    surfaceView.setLayoutParams(layoutParams); 

    surfaceView.setOnTouchListener(new View.OnTouchListener() { 

     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      if (event.getAction() == MotionEvent.ACTION_UP) { 
       // Normalize x,y between 0 and 1 
       float x = event.getX(); 
       float y = event.getY(); 

       if (x < (OptionsContainer.screenWidth) && y < screenH) { 
        NoteNode note = new NoteNode(x, y, MainActivity.options); 

        if (note.getContour() == OptionsContainer.noteList[note.getBeat() - 1].getContour()) { 
         OptionsContainer.noteList[note.getBeat() - 1] = new NoteNode(x, screenHeight + 200, MainActivity.options); 
        } else { 
         OptionsContainer.noteList[note.getBeat() - 1] = note; 
        } 
       } 
      } 

      return true; 
     } 
    }); 

    mainActivity.addContentView(surfaceView, layoutParams); 
    surfaceView.resume(); 
} 

編輯#2:最終的答案

添加Path.reset()的路徑在drawBPM()繪製後。我想可能會阻止那條路徑的內存泄漏,它試圖跟蹤它已經寫入和覆蓋的所有路徑,對於我們的知識來說,只是看着屏幕上的線條。有一個類似的堆棧溢出問題,但下面的fadden的調試技巧是很有用有助於最初試圖找出哪裏出了問題。

回答

2

「擠壓性能」和Canvas渲染並不真正在SurfaceView上一起使用,但在許多設備上都可以。

Grafika's「多表面測試」活動具有彈跳圓圈,用軟件呈現。我沒有注意到它會隨着時間的推移變慢,所以我懷疑你的代碼有問題。注意Grafika不支持SurfaceView,我通常建議不要這樣做 - 做錯事太容易。子類SurfaceView唯一有效的原因是如果你想在Surface上畫圖,爲某種掩模效果。

您沒有顯示任何代碼,所以我們可以告訴您的不多。

我在代碼中看不到任何明顯的錯誤;看起來非常簡單。我會檢查以確保OptionsContainer.noteList.length沒有限制地增長。下一步是使用traceview來確定哪部分渲染速度較慢,或者只需傳播System.nanoTime()來確定哪個部分逐漸變慢。如果顯示的方法中的所有內容都以一致的速度執行(drawCursor()除外),請將時間檢查呼叫移至該範圍內,縮小範圍,直至找到排除性能的內容。

如果某些內容消耗足夠快而導致堆問題,則應該在logcat輸出中看到大量的GC活動。DDMS allocation tracker tool可以幫助。

+0

DDMS顯示大多數內存似乎是主要的,但它與一般的觸摸事件處理和一切正常的應用程序調用。此外,所有這些位圖都被加載到內存中,但並不是每次調用都會發生這種情況。可以確認noteList沒有增長。看一下'drawCursor()'方法的時間間隔,平均大約90,000ns命中基本相同的數字。 – A13X

+0

可以確認'doDraw()'方法正在減慢。將讓你全部張貼... – A13X

+1

顯然,我所要做的只是重置'drawBPM()'方法的路徑?!現在它在屏幕上以相同的速度運行光標。非常感謝您提供調試技巧,部分答案也在這裏找到:http://stackoverflow.com/questions/9022766/are-paths-the-most-efficient-way-to-draw-changing-shapes – A13X