I'm trying to draw a route onto my MapView.
I've extended Overlay and implemented the draw() method.
The route is displayed properly, although while debugging,
I added a breakpoint on draw(), and noticed it is being called constantly.
I only want it to be re-drawn if someone moves the map or zooms (the draw take into account these changes when drawing the route)
What can cause this ?
There are two draw methods that can be overridden.
void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow)
Desc: Draw the overlay over the map.
boolean draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow, long when)
Desc: Draw call for animated overlays.
I originally overrided the second one.
After changing to the first method, it worked out.
i think the draw method is called repeatedly because the of the background being redrawn constantly. try setting the "MapView.ReticleDrawMode" to DRAW_RETICLE_UNDER. This basically tells the mapView to draw the reticle under the overlays. So overlay's draw method will not be called when the background is recalled. this fixed the issue for me.
for more info, look here: MapView Api
I got tripped up when I didn't realize that the draw method get's called not only any markers that you draw, BUT also the shadow of those markers. So as an example, if you have two markers and you have shadows set to true (which is the default setting), then you'll have the draw method being called 4 times (once for each marker, once for each shadow of the markers)!
After further review, the Overlay draw() does actually work as described in the documentation. One draw for shadow = true, and one for shadow = false.
The interesting thing is that the specific overlay draw() method responds as advertized for each element drawn in the MapView. For example, in my case, it seems to respond for each the google map, the Google logo drawn on the map, and then the particular overlay I have drawn myself. Obviously twice for each (shadow true|false).
This is probably the intended way to render the maps. I haven't found or spent enough time researching for this information.
Also, in my own case, I have a transparent panel rendered over my map with CheckBox(s) and TextView widgets. The TextView forces the draw() method to run non-stop since the textview is always listening for input and hence triggering the redrawn of the overlay.
In my app, I have an indefinite progress bar (e.g. spinning circle) show when I'm loading network data for the map. When the network data is finished loading, I was setting the progress bar's visibility to invisible. However, this caused the map to continuously redraw as it seems that any animation (I'm guessing) which takes place over the map will cause the map itself to redraw. Simple solution to this is to set the visibility to gone instead. E.g. change this:
ProgressBar loadingIcon = (ProgressBar) findViewById(R.id.loadingIcon);
...
//Network data now finished loading...
loadingIcon.setVisibility(View.INVISIBLE);
to this:
loadingIcon.setVisibility(View.GONE);
which removes it entirely from the map, no longer animates over it and therefore does not cause draw() to be called a indefinitely.
For me it looks like a strange bug - sometimes the draw method is called continously, sometimes not.
see here.
I know this is an old problem, but I just now encountered it. This is a "for what it's worth" post.
The draw loop turned out to be a coding error on my part. According to the doc, if the draw routine returns true, it is asking for an immediate update. If false is returned, only two passes are made for each overlay; one for shadow true and one for shadow false. I was returning true which resulted in a constant update. After I changed to returning false, only two passes per overlay occurred. No loop.
You can simply add this to your ItemizedOverlay class:
#Override public void draw( Canvas c, MapView m, boolean shadow ) { super.draw( c, m, false );}
This will remove the shadow from your mapview overlay.
Related
I have a question regarding the draw() method of the Overlay class in Android Maps.
When I move map, method draw() get called a few times (from 4 to 13). It's a problem for me, because this method must repaint my route with 70000+ points, and this is a lot resources.
I can't find description for this problem, but when I use code examples from any sources, I have same problem.
This is the normal behaviour. When you move the map, you expect it to move smoothly and to achive that any map movement is slipt in smaller movement steps.
For the sake of consitency, the draw() method on the overlay is called for each of this small steps movement, so you can reposition your overlay items to follow each os this steps.
You can improve it using the following:
Improvement 1
For each of the small steps, onDraw is called twice. One with shadow parameter equal to trueand one equal to false. If you are not drawing shadows you can just ignore one of the calls, and therefore reduce the overhead by 2, using the following as the first line of onDraw():
if(shadow) return;
Improvement 2
Optimize the way you are drwaing the route. If you are using canvas.drawLine() you can definitly improve it by using canvas.drawPath(). You create a path with your route just once (for a specific zoom level) and when the map is moved you just offset the path, without the need to recreat it.
Improvement 3
You can even optimize further the path, only adding points that have a distance from previous pixel bigger a speciffic value (i.e. 2 pixels), reducing the total number of points in the path without any visible loss of quality.
I'm using the approach above with routes of several thousand points (aprox 20.000) and the route move smoothly in a medium range device.
Let me know if you need more details in any of the above points.
good luck.
I suspect you use
boolean draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow, long when)
and not
void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow)
The first one is used to draw animations, so it gets called many times.
Ref: draw is being constantly called in my android map overlay
I have an android app I have written, that basically has a custom overlay, in this overlay I have overwritten the DRAW method to draw something on a canvas and at the end of my DRAW override, I call the super DRAW passing in the canvas I have painted.. the result is, every time the map is modified in anyway my custom overlay is redrawn as expected.
Now, I am trying to accomplish the same thing on iPhone and am getting a little confused.
Basically I need something drawn in the top right corner of the map every time a redraw occurs of the map. The drawin will change change with every update as well so can't simply be put a view over the map and pass touches through etc.
So, I guess the question is, what is the euivalent of the DRAW method in iOS.. how would I roughly accomplish this same thing? There are MKOverlayView in the API, but there seem to be some significant differences.. So, how do I put something say at 10x10 over the map, whos size is variable and make sure every time the map is moved, scaled or otherwised interacted with this object is redrawn at location 10x10 on the screen.
The docs for MKMapView state that you should not subclass MKMapView, so you can't / shouldn't override the drawRect method. You could add a UIView, though, and override drawRect to do your custom drawing.
I have faced some problems with the Android MapView API. I get OverlayItems from a database which I want to display in a MapView. If I'm displaying 100 Icons, I have no issues, but if it gets more - like 500 Items in one City - it first looks really bad, while second it slows down a lot. Unfortunately my goal is to display 10000 of them. I think one solution can be to register a listener to ZoomLevels to make them appear/dissapear, but I couldn't find that functionality. Second, I couldn't find a function to scale my Overlays with the Zoom of the Map.
Any Ideas are very welcome
There is a very strange behavior in ItemizedOverlay draw method. When you say: Draw line from (x,y) to (x1,y1) the draw method is called about 20-30-40 times - i don't know why. It is acceptable when you draw one line, but when you draw a thousands of lines,icons and so on...it is very very bad! To solve this problem you should create a cached overlay. This is overlay that catches the first draw, creates the object and then prevents the future draws that do the same draw.
A cluster is a dozen of icons behind one icon. For example if you have 1000 markers on the map, in a specific minimal zoom level you can not see each marker separately - it becomes a mess of icons and colors and so on. And instead of 100 markers that are very very close one by one you place a cluster marker. And on zoom in remove this cluster and create another clusters...do this until the markers became far enough away and you can seen them divided.
Check this: Cluster markers
Take the following approaches:
Create a cached overlay to prevent multiple drawing of same clusters;
Draw in thread;
Cluster your markers depending on zoom level and marker proximity.
Each time you draw in the overlay, check for sure is the current marker inside of the visible part of the screen. If it is not, do no draw it!
I had a similar problem with the icon size and zoom level in my application. What I ended up doing was having 2 sets of overlays containing the markers, one with a "zoomed in" icon and one with a "zoomed out" icon. Then just changed the overlay at a certain zoom level (using a zoom poller - On zoom event for google maps on android)
All,
I have a need to display information on a MapView object. No problems there.
The issue is that there are times when the MapView object displays map details that visually compete with my overlay data.
So, what I'd like to do is provide a way to "scale back" the MapView object visually by using an alpha channel.
Can an alpha value get applied to a MapView object? If so, how?
Alternatively, I was thinking that perhaps a separate all black overlay might provide the same results. Scale the alpha of this overlay and I might end up with the same overall effect.
Insight please.
Thanks.
Rich
Are you sure you want to do this? It might be better to revisit your overlay's graphic design... simply giving them a thicker border might be a cheap solution to the problem.
First suggestion would be to subclass MapView and override dispatchDraw() with something like this:
#Override protected void dispatchDraw(Canvas canvas) {
// Firstly let MapView draw
super.dispatchDraw(canvas);
// Draw a translucent fill on top of it
canvas.drawColor(0x7FFFFFFF);
// TODO: Draw my overlay
}
I need to redraw the overlay after the user zooms.
What is the best way to do this?
I've tried everything I can think of (saving a getZoomLevel() state, overriding onUserInteraction()), nothing actually works.
The problem is, that draw() is being called when the user clicks zoom, so the information my draw method gets (About the map's state) is different from the state after the mapview finishes zooming.
Also, draw() isn't being called at the end of the zoom, so only if I pan the map the overlay is actually being drawn properly.
As nobody has answered this in 7 months, I will write what I ended up doing.
I used a Handler to refresh the map manually after 500ms, it worked alright.
Handler handler;
handler.postDelayed(refreshRoute, 500);
Have you tried calling mapview.postInvalidate() after the zoom?