I have a scrollable and zoomable map which has a low res copy of the map which is drawn when the zoom scale is small and a tile system when the user zooms in past a certain point. The problem im having is that the very first time the tiles are drawn there is a short, but noticable lag. After that initial lag everything is smooth. The GC isnt running, and all the bitmaps are loaded at launch time. Any idea what exactly is going on so i can take care of the lag? Or any way for a work around? Thanks. Heres the code below:
canvas.drawBitmap(map, null, bgRect,paint);
if(matrix[0]>.9){
mapPicture = makeMyMap(xScale,yScale); //make/update our map.
mapPicture.draw(canvas);
}
Try switching on tracing with DDMS to establish which methods take a long time on the first draw and see how they compare with the subsequent draws.
It's possible that drawBitmap is triggering the platform level up-scale / down-scale of the images on first draw rather than load - but that's speculation on my part.
Related
I've noticed my whiteboard app becomes 'dormant' after a few seconds of no interaction, so that when something is newly drawn, there is horrible lag. This is without switching away from the app at all - I run it, it's there, I can draw and undo. But if I don't use it for 10 seconds and then try and draw a circle, there can be a second or so of wait before it updates and I get a straight line from start point to current position. So the code to start drawing is instant when the view is touched, but the updates aren't happening for a good while yet.
The code is effectively the Fingerpaint demo drawing onto a custom bitmap, and I copy this bitmap to the view. I undo by copying the bitmap just before drawing starts. I have disabled the undo code to see if that was the issue, but the delay is still there, only far less pronounced. I notice the same lag sometimes happens in the Fingerpaint API demo.
Anyone know why this is? Is there some odd setting I don't know about which causes an active app to go to sleep?
I'm writing a simple 2D game engine and rendering various objects to a locked SurfaceVew by calling Canvas.drawBitmap (all the same source bitmap but generally not with 1:1 source to destination scaling).
Everything appears to work as expected until there are a lot of calls per frame to drawBitmap. When this happens I occasionally see a stall (100mS or so) accompanied by an effect that looks as if several frames of rendering have occurred together, i.e. some objects will be drawn twice at two screen locations or a pair of objects moving at the same speed will appear to momentarily get closer together or further apart.
The application is structured as follows (simplified for the sake of example);
initialiseGameObjects();
while(quit==false)
{
processGameLogic(); // update object positions
Canvas c = surface_holder.lockCanvas();
if (c != null) {
drawGameObjects(c); // draw all objects
surface_holder.unlockCanvasAndPost(c);
}
}
As I understand it, the Canvas is a holder for draw requests which get executed when the Post is issued. Presumably there is a limit to the number of requests it can hold and I'm wondering if I'm exceeding this limit (I'm drawing up to a hundred small bitmaps depending on what's on screen at any one time) and inadvertently provoking some kind of flush and upsetting the double buffering in some way, although I've not managed to find any documentation to confirm or disprove this.
Does anyone have any idea what might be going on?
Regards,
Steve
You need to sychronize calls to canvas drawing. Check this example of a game driving thread: OnDraw() is not fired, nothing is drawn in surfaceView - Android
EDIT:
However I think it may be related to this problem:
Android SurfaceView/Canvas flickering after trying to clear it
Currently I have a cartoon character that takes up almost the full screen of a surfaceview, and my little app is only to animate this 2D character during ontouch event at different coordinates.
What I am doing now is to redraw the whole character every single time, and this way I need to have a specific graphic for every single frame.
I am just wondering if its better to split the character into different parts, e.g. heads, hands, legs, and whenever a ontouch event happens, I only need to re-draw the specific part?
What do you think the pros and cons would be? Is it less CPU intensive?
This really comes down to how your images are set up.
Having a single image taking up the whole screen means that every frame has to redraw the whole screen, something which an android device should be capable of doing. If you break your character into different parts it may look as if you only have to redraw a small part of the screen but if you just redraw one part around then it will still be in its old position unless you draw over it meaning you may have to do a full redraw anyway. Sometimes you can be clever and work out what areas of the screen need to be redrawn and then only redraw those but this can get very complicated.
Another think worth thinking about is memory usage though, if you have a large number of full screen images in memory some phones may not have enough available memory and may crash. By breaking the image up into small parts you should reduce the chance of this.
I'm tried to determine the "best" way to scroll a background comprised of tiled Bitmaps on an Android SurfaceView. I've actually been successful in doing so, but wanted to determine if there is a more efficient technique, or if my technique might not work on all Android phones.
Basically, I create a new, mutable Bitmap to be slightly larger than the dimensions of my SurfaceView. Specifically, my Bitmap accomodates an extra line of tiles on the top, bottom, left, and right. I create a canvas around my new bitmap, and draw my bitmap tiles to it. Then, I can scroll up to a tile in any direction simply by drawing a "Surfaceview-sized" subset of my background Bitmap to the SurfaceHolder's canvas.
My questions are:
Is there a better bit blit technique than drawing a background bitmap to the canvas of my SurfaceHolder?
What is the best course of action when I scroll to the edge of my background bitmap, and wish to shift the map one tile length?
As I see it, my options are to:
a. Redraw all the tiles in my background individually, shifted a tile length in one direction. (This strikes me as being inefficient, as it would entail many small Bitmap draws).
b. Simply make the background bitmap so large that it will encompass the entire scrolling world. (This could require an extremely large bitmap, yet it would only need to be created once.)
c. Copy the background bitmap, draw it onto itself but shifted a tile length in the direction we are scrolling, and draw the newly revealed row or column of tiles with a few individual bitmap draws. (Here I am making the assumption that one large bitmap draw is more efficient than multiple small ones covering the same expanse.)
Thank you for reading all this, and I would be most grateful for any advice.
I originally used a similar technique to you in my 'Box Fox' platformer game and RTS, but found it caused quite noticeable delays if you scroll enough that the bitmap needs to be redrawn.
My current method these games is similar to your Option C. I draw my tiled map layers onto a grid of big bitmaps (about 7x7) taking up an area larger than the screen. When the user scrolls onto the edge of this grid, I shift all the bitmaps in the grid over (moving the end bitmaps to the front), change the offset of grid, and then just redraw the new edge.
I'm not quite sure which is faster with software rendering (your Option C or my current method). I think my method maybe faster if you ever change to OpenGL rendering as you wouldn't have to upload as much texture data to the graphics card as the user scrolls.
I wouldn't recommend Option A because, as you suggest, the hundreds small bitmap draws for a tiled map kills performance, and it gets pretty bad with larger screens. Option B may not even be possible with many devices, as it's quite easy to get a 'bitmap size exceeds VM budget' error as the heap space limit is set quite low on many phones.
Also if you don't need transparency on your map/background try to use RGB_565 bitmaps, as it's quite a lot faster to draw in software, and uses up less memory.
By the way, I get capped at 60fps on both my phone and 10" tablet in my RTS with the method above, rendered in software, and can scroll across the map smoothly. So you can definitely get some decent speed out of the android software renderer. I have a 2D OpenGL wrapper built for my game but haven't yet needed to switch to it.
My solution in a mapping app relies on a 2 level cache, first tile objects are created with a bitmap and a position, these are either stored on disk or in a Vector (synching is important for me, multithreaded HTTP comms all over the place).
When I need to draw the background I detect the visible area and get a list of all the tiles I need (this is heavily optimised as it gets called so often) then either pull the tiles from memory or load from disk. I get very reasonable performance even on slightly older phones and nice smooth scrolling with no hiccups.
As a caveat, I allow tiles not to be ready and swap them with a loading image, I don't know if this would work for you, but if you have all the tiles loaded in the APK you should be fine.
I think one efficent way to do this would be to use canvas.translate.
On the first drawing the entire canvas would have to be filled with tiles. New android phones can do this easily and quickly.
When the backround is scrolled I would use canvas.translate(scrollX, scrollY), then I would draw individualy one by one tile to fill the gaps, BUT, I would use
canvas.drawBitmap(tileImage[i], fromRect, toRect, null) which would only draw the parts of the tiles that are needed to be shown, by setting fromRect and toRect to correspond to scrollX and scrollY.
So all would be done by mathematics and no new bitmaps would be created for the background - save some memory.
EDIT:
However there is a problem using canvas.translate with surfaceView, because it is double buffered and canvas.translate will translate only one buffer but not the second one at the same time, so this alternating of buffers would have to be taken into account when depending on surfaceView to preserve the drawn image.
I am using your original method to draw a perspective scrolling background. I came up with this idea entirely by accident a few days ago while messing around with an easy technique to do a perspective scrolling star field simulation. The app can be found here: Aurora2D.apk
Just tilt your device or shake it to make the background scroll (excuse the 2 bouncing sprites - they are there to help me with an efficient method to display trails). Please let me know if you find a better way to do it, since I have coded several different methods over the years and this one seems to be superior. Simply mail me if you want to compare code.
In my app I am drawing bus routes on top of a MapView. The routes have anywhere between a dozen and a few hundred GPS coordinates that describe the route that the bus takes.
The problem I'm having is that once I draw out all these lines panning/zooming the MapView is incredibly slow (even clicking the 'Back' button takes a minute to happen).
I'm not sure how relevant it is, but I put in some debug code then checked the logcat output and the MapView is repeatedly calling the draw() method of the Overlay whether anything has changed or not. This is happening several times a second and is causing a massive amount of garbage collection to happen (2-3 MB every second).
Does anyone have any ideas/suggestions for a method to try and speed this up?
I have only used ItemizedOverlay, not Overlay, so these suggestions are pure conjecture. Heck, I haven't even done much with the 2D graphics API.
Obviously, the best answer is to get it to stop calling draw() all the time. Try logging some stack traces and see if you can figure out what is triggering all of the draw() calls. For example, in the Android Google Groups recently, somebody noticed that Chronometer causes widgets in the same UI to be redrawn every second. While I can see you don't have a Chronometer, you might be able to figure out some root cause to the draw() calls that you can correct.
Assuming that does not help, I am guessing that the test for "whether anything has changed or not" is some combination of getLatitudeSpan(), getLongitudeSpan(), getZoomLevel(), and maybe other MapView methods. And, I am assuming that on every draw() you are iterating over your GPS points and drawing the route. If so, you could try:
When you really do draw, draw first to a Canvas backed by a Bitmap, then apply the Bitmap on the Canvas you are handed in draw(), and cache that Bitmap.
Track what combination of values were used in the last draw(), and if the next draw() is the same, just reuse the existing Bitmap. Else, go to step #1, making sure to release the Bitmap (or reuse it, if that's possible).
I am guessing that with graphics acceleration, blasting a Bitmap onto the Canvas is cheaper than iterating over the coordinates and drawing lines. And, by caching the Bitmap, you will save on garbage generation.
Anyway, just a thought.
There are two draw methods in the overlay class. One with 3 arguments and one with 4 arguments. You have to override the draw method with 3 arguments.
Overriding the method with 4 arguments will slow down your application. This is exactly, what happened to me. It seems, where are examples around in the internet with the same error.