2016-06-09 130 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