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.
Related
I just did an experiment, a big ImageView in full-screen size and a small ImageView in the center. I changed the src of small ImageView and only small ImageView's onDraw is called.
I was wondering if the big ImageView's onDraw wasn't called, why can I see it on screen?
I guess the GPU rendering is based on the last snapshot of the GPU buffer and only submits the change in every VSYNC. So if there's no change in this area, it will show the content as the last frame.
Am I wrong? Please give me your idea about this.
Only the views that change need to be redrawn. Why would the rest need to be?
What happens when you change the image in an imageView is that it calls invalidate() on that view. This marks the view as dirty and needing a redraw. This will cause its onDraw to be called on the next render pass. Views that aren't invalid don't change, thus don't need their onDraw called.
I'm using a viewpager to show static information to the user, this includes textviews, imageviews, etc. Now my swiping of my viewpager isn't really fluid when I include images to my viewpager. So I used the hierarchy viewer to check how much time it cost to draw my images. To draw only one image (filetype: JPG, filesize: 40kB) it took more than 50ms to actually draw it. So every time the screen is redrawn (during swiping from the user) it will take up more than 50ms to fully redraw the screen, what I suspect to be the culprit of the 'swiping lag'.
Does anybody know a way to improve the drawing speed of the images? I searched through the topics here, but couldn't find a definite answer to my problem.
Thanks in advance!!
implement image loader to load image in your viewpager will increase scroll speed try This
If all the images are stored locally then while drawing them in the layout write your code in OnDraw() method of Pager Adapter.It will not take any time.
to call onDraw() use this
Call this method in the onDraw function:
protected void onDraw (Canvas canvas) {
drawyourImages(canvas);
}
Every time when your UI is refreshed, the onDraw function will be called. To trigger the UI refresh. Just invalidate your custom view. For example
mCustomerView.invalidate();
OR
if your image is coming from server then use AQuery/Picasso or any image loading library to load your image in onDraw() method.before calling onDraw() you have to invalidate your view.To invalidate your view you should call
mCustomerView.invalidate();
in viewpager swipe method listener.
I have created a custom view to be shown in the action bar. It mostly works except sometimes on start I see a mirror copy of whatever I draw. The copy overlaps the original one but a few pixels away.
My onDraw() override is quite simple. All it does is draws an image that is centered in the canvas.
I am a bit confused. Am I expected to clear the canvas first in onDraw() method? Thank you in advance for your help.
It is confusing, but you'll notice in the custom view samples (that come with the sdk), the onDraw() method first calls canvas.drawColor() before anything else.
I assume it's not done automatically because it would be wasteful in the case where what you were drawing filled the entire view anyway. I just wish it was more clear that it is necessary in most cases.
Here is what I found out that others may find useful. If you set a background using setBackground(), the framework will actually draw the background before calling onDraw(). This background is drawn in the center. I too was drawing the background in onDraw() but I was drawing it from top-left. Hence, I was seeing the ghost image.
As Krylez mentioned, you may wish to call drawColor() as your first call in onDraw().
What I did was overrode setBackground() and its variations, and stored the background bitmap in a local variable.
Regards,
Peter
I have made my own canvas class which extends an imageView. My onDraw() method draws out the users gps position and I keep calling this onDraw method every time the user moves. My problem is I also want to draw out a gps trail which only needs to be drawn once (doesnt need to be updated when a user moves). I am wondering is it possible to have more than 1 onDraw method or is there any way of separating 1) the user location and 2) the gps trail??
My reason is I do not want to waste memory by redrawing the gps route everytime the users gps position changes. It is a waste.
Have you seen performance take a hit? If not, don't worry about it. I would think that this would be wasting CPU cycles if anything... not memory. So if the app seems fast enough already, don't worry about optimizing it.
If your app is a bit laggy, and you've found that the trail is the bottleneck... I would suggest caching it into a bitmap. This way, you will still have to draw the trail, but you will not have to calculate the coordinates of the trail on each frame.
I have had to solve a somewhat similar problem recently and I'll explain briefly what I did in case it's of any help.
What you can do is use multiple overlapping Views, where one may contain the background graphics that you don't want to redraw often, and a foreground View that contains the graphics that are frequently updated. Then, to gain performance, you can design the background View's onDraw() so that it is backed by a Bitmap that you then retain as a class variable. In the very first onDraw() of your background graphics, you do the relatively slow drawing to Canvas. In subsequent calls to onDraw(), you simply draw that Bitmap to Canvas.
I've just done this myself. Basically what my application does is display a number of graphical gauges. Those gauges have lots of graphics that are drawn just once (gauge face, number legends), and the pointer graphic that needs to be redrawn over and over as the model data changes. First of all, I split the background graphics and moving foreground graphics into separate overlapping Views. Now, invalidating and redrawing the foreground pointer graphic of course causes anything it overlaps to be invalidated too, so the onDraw() method for the background graphics View is being called each time the pointer View is redrawn. The background View only needs to draw the background graphics once, but retains the Bitmap that backs the canvas, and in subsequent onDraw() calls it draws this bitmap back to Canvas (which is a lot faster than initially creating the graphics using Path() objects).
Bitmap bm;
....
protected void onDraw(Canvas canvas){
if(null==bm){
bm=Bitmap.createBitmap(getMeasuredWidth(),getMeasuredHeight(),Bitmap.Config.ARGB_8888);
// do your slow vector graphics drawing to Canvas here
}
Paint drawPaint = new Paint();
drawPaint.setAntiAlias(false);
drawPaint.setFilterBitmap(false);
drawPaint.setDither(false);
canvas.drawBitmap(bm, 0, 0, drawPaint);
}
Well, there can't be more than 1 onDraw method, assuming that I understood your question correctly. You will need to think about alternate approaches about how to handle this.
#DeeV suggested, that can be a solution for you.
I'm creating a custom TextView by using TextPaint in the onDraw() method.
however this is causing severe problems for my app.
performance wise I mean.
The onDraw() method gets called over and over again .
but i just want it to draw once :(
i tried using setDrawingCacheEnabled(true); but no effect there.
There is also a viewflipper with textviews in the main layout rotating automaticly,
could this be causing everything to redraw ?
can anyone give me some pointers here ?
As well as enabling the drawing cache, try creating a new bitmap instance in the inDraw and pass that to the Canvas to draw to. In the next call to onDraw, simply draw that bitmap if it is not null. I'm doing this myself and it works a charm to improve performance, though unable to copy the code right now (out using phone).
As for why it is being consistently redrawn, are there any moving overlapping graphics causing it to be invalidated?