I am trying to construct a SurfaceView by reading in an array and using case switches to build the canvas.
so the question is: can I construct a canvas looping Y, by tracking X. loading bitmaps using BitmapFactory() into the canvas and then using 1 .show() to render the canvas to the screen? or will I need to call the canvas render for each of these (or will that through away the screen every time I do that)?
Not sure what you're getting at, but for one thing avoid using BitmapFactory in onDraw. You don't want to be doing bitmap decoding at the same time as rendering. You should load your bitmaps ahead of time and keep them around in memory for faster drawing later on.
Related
Use case:
I need to draw hundred lines and a few pieces of text on my view. I need to give a scrolling effect, for which I capture the ACTION_MOVE event and redraw all the lines with the updated points. To get the desire result I tried with different approaches but none works as intended.
Approach 1
I made a custom class which extends View. All the drawing and calculation is done directly in my onDraw() method. Since there is so much of operation done in onDraw() method, the performance of the app is very poor. I even checked the performance using Profile GPU rendering and I can see the lines are very tall.
Approach 2
I created a Bitmap and after drawing all the lines onto my bitmap in another thread, I used postInvalidate() to draw the bitmap in onDraw() method:
mBufferedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
mBufferedBitmap.eraseColor(Color.TRANSPARENT);
Canvas mBufferedCanvas = new Canvas(mBufferedBitmap);
drawLines(mBufferedCanvas)
postInvalidate();
Since I erase all the previous drawing on the bitmap and draw new lines with updated points, there is a flickering on the screen.
Approach 3
I tried extending my custom class to SurfaceView and performing all the operations on canvas object in another thread. But since SurfaceView uses CPU for drawing operations, the performance will be poor in low configuration mobiles.
Can anyone guide me how to achieve this task with better performance?
It is possible to use your approach 1 to achieve good performance.
An example that sounds close to your use case (drawing lines, a little text and having these update on gesture movement) is MPAndroidChart. This is an open source library that achieves high performance (see the following comparison if you want stats)
The classes to examine are the Renderer classes as these contain code draw in the onDraw(Canvas c) of the chart subtypes. You can see some of the tricks used to achieve high performance there:
Don't allocate in a render loop. Instead, allocate outside the loop and reuse/recycle variables. See LineChartRenderer line 199
Use buffering. For example, in MPAndroidChart, the points for the four corners of the bars in the bar chart are buffered and the buffer array is reused. See the BarBuffer class.
Use the native Canvas drawing functions (drawPath, drawLine etc.)
A complete list of tips for optimising rendering can be found in the Android Performance Slow Rendering Guide
Approach 2 is the best one. If you see flickering, it means that the bitmap is drawn to screen after you erase it and before you draw all the lines. If this is the case use another bitmap and do double buffering:
ScreenBitmap is what is drawn to screen
OffScreenBitmap is used for drawing in background.
Draw all your lines and text to OffScreenBitmap, and once finished, copy it to ScreenBitmap.
in onDraw, draw the ScreenBitmap.
Create these bitmaps once (typically in onSizeChanged), so that there is no alloocation in onDraw
I have an app that allows the user to draw grids of circles, rectangles, arrows, and paint. All of these are drawn on bitmaps which are in turn drawn on my main canvas. I have it structured this way because the users can zoom/pan on the main canvas (via a main bitmap) as well as move/scale/rotate each drawn object. The problem is that all these bitmaps eat up all of my memory, so I have been trying to find a better solution.
LRUcache is out of the question because I need all of the bitmaps every time the onDraw method is called, which is every time something new is drawn.
I have seen the Bitmap.getPixels() function and the Canvas.drawPoints(); function. Is there a way to use these together so I can get rid of my bitmaps? What I envision is creating a bitmap, drawing the object on it, extracting the pixels from that bitmap, and then recycling the bitmap to free up that memory. Is that feasible?
I'm making an app in which the user draws patterns (drawn and stored as Path objects) onto a Canvas on a SurfaceView. The app does some basic animations on the paths including constantly rotating them. I've read that a common optimisation for Path drawing is to cache them into a Bitmap so that all the bezier logic isn't repeated each frame. I tried this but it's making things worse. My best guess is that having to rotate bitmaps by an arbitrary angle every frame is too expensive. Is this a likely diagnosis? Bitmap rotation is very slow, right? Is there a way around this?
I want to make brushes displayed in below image for drawing application. Which is a suitable method - Open GL or Canvas & How can we implement it?
I'd say Canvas, as you'll want to modify an image. OpenGLES is good for displaying images, but does not (as far as I know) have methods for modifying its textures (unless you render to a texture that then render to screen with some modifications, which is not always so effective).
Using the Canvas you will have the methods for drawing your brush-strokes onto the Bitmap you're painting on, in GLES you would have to modify a texture (by using a canvas) and then upload that to the GPU again, before it could be rendered, and the rendering would most likely just consist of drawing a square with your texture on it (as the fillrate for most mobile GPUs are quite bad, you don't want to draw the strokes separately).
What I'm trying to say is; The most convenient way to let the user draw on an openGLES surface would be by creating a texture by drawing on a Canvas.
But, there might still be some gain in using GL for drawing, as the Canvas-operations can be performed off-screen, and you can push this data to a gl-renderer to (possibly) speed up the on-screen drawing.
However; if you are developing for Android 3.x+ you should take a look at RenderScript, (which I personally have never had a chance to use), but seems like it would be a good solution in this case.
Your best solution is going to be using native code. That's how Sketchbook does it. You could probably figure out how by browsing through the GIMP source code http://www.gimp.org/source . Out of Canvas vs OpenGL, Canvas would be the way to go.
It depends. if you want to edit the image statically, go with canvas. But if you want after brushing the screen, to have the ability to edit, scale, rotate, it would be easier with opengl.
An example with opengl: Store the motion the user do with touchs. create a class that store a motion and have fields for size, rotation etc. to draw this class, just make a path of the brush image selected following the stored motion.
I'm currently writing an Android game using surfaceView. I've optimized the game as much as possible and it runs quite smoothly. However, I have collision detection incorporated which is a bit messy. I would like to do collision detection by reading pixels directly from the canvas. Is this possible to do? The closest to this that I have found was to attach a new bitmap to the canvas using setBitmap. Then when I drew to the canvas, the bitmap would be updated. Would this be the way to go? Thanks.
Although you should manage the collision detection in a different way, you can get the pixel color on a given position with the next line of code:
mView.mBitmap.getPixel(j, i)
mView is the View that contains your canvas and mBitmap is the Bitmap with which you created your canvas:
Canvas mCanvas = new Canvas(mBitmap);
From the Canvas API:
The Canvas class holds the "draw"
calls. To draw something, you need 4
basic components: A Bitmap to hold the
pixels, a Canvas to host the draw
calls (writing into the bitmap), a
drawing primitive (e.g. Rect, Path,
text, Bitmap), and a paint (to
describe the colors and styles for the
drawing).
So you wouldn't ever ask a canvas for pixel data, because the canvas itself doesn't really "own" pixel data. The canvas which you use to make draw calls is always attached to a bitmap (the one you're drawing on), so that bitmap is where you should get your pixel data from.
Collision detection is usually costly, but going to a bitmap-based process could make it even worse, depending on what you're trying to do. Just a heads up.
I agree with Josh. If precision is that important in your app, you may want to incorporate screen size/resolution data into some kind of physics engine. Trying to build a physics engine based entirely on visual processing is probably unnecessarily costly.