这种画布绘制方法如何使我的应用程序变得如此糟糕?

时间:2015-12-14 17:18:29

标签: java android performance canvas

我最近遇到的问题是我锁定的SurfaceView画布上的canvas.drawArc() - 方法会显着减慢我的应用程序的加载和恢复时间。我绝对相信带注释的代码行主要导致这个问题,但我还附上了一些可能与你相关的其他代码。

surfaceView.surfaceCreated() - 方法中创建的线程(可能不太相关)

while(true) {
    while (!running()) {
        try {
            sleep(50);
        } catch (Exception ignore) {

        }
    }

    try {
        surfaceView.canvas = holder.lockCanvas();
        synchronized(holder) {
            surfaceView.draw();
        }
    } catch(Exception ignore) {

    } finally {
        try {
            holder.unlockCanvasAndPost(surfaceView.canvas);
        } catch(Exception ignore) {

        }
    }
}

最有可能导致问题的实际draw() - 方法:

// other draw methods, including a bitmap, ovals from float[]-Arrays, paths and text

Paint paint = new Paint();
paint.setColor(0x33d0d5c9);
paint.setStyle(Paint.Style.FILL);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);

ArrayList<float[]> particles = new ArrayList<>();
while(particles.size() < 200) {
    particles.add(new float[]{x1, y1, x2, y2});
}

// completely removing the following loop prevents the problem
for(float[] p : particles) {
    // draw overlapping particles on the canvas (a path would affect the look)
    canvas.drawOval(new RectF(p[0], p[1], p[2], p[3]), paint);
}

我非常感谢您就如何优化我的代码以便正常工作提出建议。

编辑:我的解决方案基于lukasrozs answer

final Canvas canvas = canvas;
Thread particleThread = new Thread(new Runnable(){
    @Override
    public void run() {
        RectF rect = new RectF();
        for(float[] p : particles) {
            rect.set(p[0], p[1], p[2], p[3]);
            canvas.drawOval(rect, paint);
        }
    }
});
particleThread.start();

// some stuff

try {
    particleThread.join();
} catch(Exception ignore) {

}

2 个答案:

答案 0 :(得分:1)

My best guess is that you are creating to many objects in your onDraw method. Try to move the creation of the particles outside (in the constructor, or just do it once), and only set the new x,y and size values in the draw method.

Creating new objects in the onDraw method also increases the risk of the garbage collector to be triggered, so its best to avoid it ...

答案 1 :(得分:1)

You don't have to use ArrayList and float[] at all. Also, you don't have to initialize/construct new RectF every time.

// other draw methods, including a bitmap, ovals from float[]-Arrays, paths and text

Paint paint = new Paint();
paint.setColor(0x33d0d5c9);
paint.setStyle(Paint.Style.FILL);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);

RectF rect = new RectF();
for(int i = 0; i < 200) {
    rect.set(x1, y1, x2, y2);
    canvas.drawOval(rect, paint);
}

If you can, you should execute this method in another thread.

new Thread(new Runnable(){void run(){
    // draw all the ovals on canvas
    context.runOnUiThread(new Runnable(){void run(){
        // this will be executed in main thread when drawing finishes
    }});
}}).start();