Why is algorithm so slow?
I'm creating a line graph, and the code I originally used was so slow at drawing that it was useless. I replaced it with code I found online and it became much faster. I was just curious as to why the original code is so slow. All of the code posted below is inside the onDraw() method of a custom view:
Original slow code:
float yStart = 300f;
for (int i=0; i < values.length; i++){
drawPath.moveTo(xStart, yStart);
drawPath.lineTo(xStart+10, values[i]);
drawPath.close();
canvas.drawPath(drawPath, linePaint);
xStart += 10;
yStart = values[i];
}
Later fa开发者_开发知识库st code:
float datalength = values.length;
float colwidth = (width - (2 * border)) / datalength;
float halfcol = colwidth / 2;
float lasth = 0;
for (int i = 0; i < values.length; i++) {
float val = values[i] - min;
float rat = val / diff;
float h = graphHeight * rat;
if (i > 0)
canvas.drawLine(((i - 1) * colwidth) + (horStart + 1) + halfcol, (border - lasth) + graphHeight, (i * colwidth) + (horStart + 1) + halfcol, (border - h) + graphHeight, linePaint);
lasth = h;
I just don't understand why one is so much more efficient than the other. Any ideas?
It is CLEAR
In the first piece, there are three operations on objects {moveTo, lineTo, drawPath, and close}
Int the second piece, it is all float operations except one operation on objects
Using Path
s makes the drawing significantly slower than simply telling the Canvas
to draw a straight line between two points since Path
is a much more complex object than the 2 points that drawLine()
uses. Path
s are also filled and framed based on the Style
in the Paint
which could also cause a slowdown.
In general, using objects and calling a lot of methods in a loop slows down your code.
After a bit of search, the problem probably came from where I said : you should only call moveTo for the first point of the graph, and then only call lineTo in the loop. When the path is defined entirely (after the for loop) you may draw it. The path is optimized for your purpose, but you where not using it correctly.
http://developer.android.com/reference/android/graphics/Path.html#lineTo%28float,%20float%29
I think you should do it like this:
float yStart = 300f;
drawPath.moveTo(xStart, yStart);
for (int i=0; i < values.length; i++){
drawPath.lineTo(xStart+10, values[i]);
xStart += 10;
yStart = values[i];
}
drawPath.close();
canvas.drawPath(drawPath, linePaint);
otherwise you will draw on the canvas the "building" of drawPath X times.
Also you can precalculate the path and have only the canvas.drawPath in the onDraw.
Also, you should use path.reset() to clear up the memory. Otherwise, every time you draw a different object using the same path it's gonna draw ALL of the objects you've drawn before using that path. So the complete code, would be.
float yStart = 300f;
drawPath.moveTo(xStart, yStart);
for (int i=0; i < values.length; i++){
drawPath.lineTo(xStart+10, values[i]);
xStart += 10;
yStart = values[i];
}
drawPath.close();
canvas.drawPath(drawPath, linePaint);
drawPath.reset();
精彩评论