I've seen some code on this site that does that but I don't understand how it can work. From what I understand, AsyncTask is only suitable for tasks of only a few seconds and only executed once. For drawing bitmap on a canvas, it has to be redrawn over and over to be displayed on the canvas so I don't see how AsyncTask can work.
Will it be advisable to draw Bitmap on canvas using AsyncTask?
Thanks
You are right, Async tasks are best used for something that is only executed once. As a result, You could possibly use an AsyncTask to decode the bitmap and store it in a variable.
This variable can then by used to render the bitmap in the onDraw()
A SurfaceView might also be more useful for what you need.
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?
Android experts, I need some help. I'm an Android noob. I have an application where I need to draw a bitmap using canvas from outside the main UI thread. I stumbled onto the SurfaceView class and mocked up a quick demo. I created a seperate bitmap instance and draw into it. When the OnDraw for the surfaceView occurs, I copy this bitmap into the SurfaceView. It works great until the activity ends by, for example, going back to the home screen. At that point, the SurfaceView thread seems to stop, and I seem to lose the bitmap image I was working on. When you return to the app, it starts all over from scratch.
I would like to create the bitmap image using the canvas 2D drawing calls from a thread that is seperate from the main UI thread for performance reasons. I need to get that bitmap into the main user interface once in awhile. And I need the bitmap image to be retained and continue to be drawn into (to keep it current) when the activity is paused or stopped.
Since you must do all drawing in the main UI thread the SurfaceView seems like the only solution. But it doesn't quite work like I hoped either.
I need a background task or thread that NEVER stops running and I need to create a bitmap image there, and I need to get that bitmap into the main user interface once in awhile (say 10 hz updates).
HELP! How do I do this?
Use an asynctask to draw the image onto your ui.
However, the canvas needs to be redrawn when the app is re-opened. If you want to save the bitmap that you created you will need to store it somewhere. I think this can be handled using caching:
view.setDrawingCacheEnabled(true);
Else look into managing the bitmap yourself:
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
i have written a litte app that should display a tacho that gets it data about rpm... over bluetooth. when the data changes i rotate a needle and some other imageViews to display the current values on the screen.
rotate code:
bMapRpm=bMapcanvasBackTacho.copy(bMapcanvasBackTacho.getConfig(), true);
canvasRpm.setBitmap(bMapRpm);
canvasRpm.save();
canvasRpm.rotate((float)Rpmdegree+(float)Rpmcurrentdegree,bMapRpm.getWidth()/2,bMapRpm.getHeight()/2);
canvasRpm.drawBitmap(bMapNadel,0,0,paint);
canvasRpm.restore();
bMapcanvasBackTacho is just a transparent background.
bMapNadel is the bitmap of the needle.
bMapRpm is the bitmap of the canvas to draw on
to update the imageView i allways call:
ivNadel.setImageBitmap(bMapRpm);
i tryed out what slows the app by commenting parts of the code out.
after commenting the setImageBitmap() out the slow down disapeared.
doese someone know how to update the imageView in an other way or whta i could change to get it to work faster?
thx =)
You can do two things:
First, don't call copy() each time you need to update the Bitmap this creates a new Bitmap and is both time and memory consuming.
Second, call invalidate() on the ImageView. This will notify the View that something has changed and it redraws itself without having to update anything else that is happening when you replace the Bitmap completely.
In the end you might even want to create your own View implementation so you can just override onDraw() and perform rotations there.
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.