I am trying to setup a mylocationoverlay. Unfortunately, it is acting quite strangely. It works fine, except it does not appear until after I leave the MapActivity and come back in my application. Initially the map appears and there is a blue circle while it is getting a fine location. However, instead of resolving to a point, the circle just disappears.
My Code looks like this:
onResume() {
myLocation = new MyLocationOverlay(getActivity(), mp);
myLocation.enableMyLocation();
myLocation.runOnFirstFix(new Runnable(){
public void run() {
map.getOverlays().clear();
map.getOverlays().add(myLocation);
map.postInvalidate();
}
}
}
onPause() {
myLocation.disableMyLocation();
layout.removeView(map);
map = null;
}
Does anyone have any thoughts on what might be happening here? Since this is pretty much verbatim what all the examples online look like, I might add that I am testing this on a motorolla atrix running 2.3.4.
Edit : Let me take you through your code:
onResume() {
// First time: draw a circle somewhere here. There is no GPS fix yet, so no dot.
// Second time: The dot from the previous fix exists, so you get a circle and dot.
myLocation = new MyLocationOverlay(getActivity(), mp);
myLocation.enableMyLocation();
myLocation.runOnFirstFix(new Runnable(){
public void run() {
// First time: removes the circle and draws a dot.
// Second time: removes the circle and dot, and draw a new dot.
map.getOverlays().clear();
map.getOverlays().add(myLocation);
map.postInvalidate();
}
}
}
map.getOverlays().clear(); removes the circle
use remove() instead to remove the overlay(s) that you don't want, instead of clearing them all.
Remember to call map.invalidate(); whenever you need to force a redraw
Related
I am displaying a large number of overlays on a map; the process takes 5-10 seconds. Rather than using a progress bar I want the overlays to appear gradually on the map over this time.
So for every 25 lines that are calculated I am trying to show them before continuing:
for (KmlRoad road :roads)
{
// 25 lines in this array
Polyline pline = new Polyline();
pline.getOutlinePaint().setColor(Color.RED);
pline.setPoints(road.points);
map.getOverlayManager().add(pline);
++roadsShown;
}
map.invalidate();
progressText.setText(roadsShown + " roads");
But nothing happens for a while and then all the overlays (several hundred of them) appear at once. The 'progressText' isn't updated, either.
I have also tried doing the calculation part in an async task, and sending an intent to the map activity for every 25 lines. It gives the same result, unless I add
SystemClock.sleep(xx);
to to async task, which seems very crude and is only guessing at how long the lines take to draw. Here's the code in the async task, which is called every time 25 lines have been calculated:
private void sendRoads(ArrayList<KmlRoad> roads25)
{
ArrayList<KmlRoad> theseRoads = new ArrayList<>(roads25);
// prepare array for next batch while we deal with this one
roads25.clear();
Intent intent = new Intent("newRoads");
intent.putParcelableArrayListExtra("newRoads", theseRoads);
LocalBroadcastManager.getInstance(activity).sendBroadcast(intent);
// procSpped is a crude assessment of how slow the device runs,
// generated by doing a repeat loop of math functions
SystemClock.sleep(2 * activity.procSpeed);
}
... and (if using the async method) the receiver in the main activity, which surrounds the line-drawing code above:
private final BroadcastReceiver onNewRoad = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
ArrayList<KmlRoad> roads = intent.getParcelableArrayListExtra("newRoads");
....
....
}
};
What can I do to make this show as intended?.
Its rather easy, also its just a work around....
get the current center of your map like
// MyMap is the osmdroid.MapView in the AndroidActivity
GeoPoint center = this.MyMap.getMapCenter();
and now set this center to map:
this.MyMap.getController().setCenter(center);
this forces your Map to refresh, like a manual movement would do the same
BestRegards
I am using the skobbler sdk for maps.
I use this code to center map view on current position, but even though the blue dot is at my correct current position in Los Angeles (I verify by manually going there), the map centers me at gps(0,0).
public void onCurrentPositionUpdate(SKPosition currentPosition) {
this.currentPosition = currentPosition;
mapView.reportNewGPSPosition(this.currentPosition);
if(firstPositionUpdate){
firstPositionUpdate = false;
mapView.centerMapOnCurrentPosition();
}
}
and heres my code for initializing the map:
private void initializeMapView() {
currentPositionProvider = new SKCurrentPositionProvider(getActivity());
currentPositionProvider.setCurrentPositionListener(this);
if (DemoUtils.hasGpsModule(getActivity()) && ((LocationManager)getActivity().getSystemService(Context.LOCATION_SERVICE)).isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
currentPositionProvider.requestLocationUpdates(true, true, true);
}
SKMapViewHolder mapViewGroup = (SKMapViewHolder) getView().findViewById(R.id.map_surface_holder);
mapView = mapViewGroup.getMapSurfaceView();
mapView.setMapSurfaceListener(this);
mapView.getMapSettings().setFollowerMode(SKMapSettings.SKMapFollowerMode.NONE);
mapView.getMapSettings().setMapRotationEnabled(true);
mapView.getMapSettings().setMapZoomingEnabled(true);
mapView.getMapSettings().setMapPanningEnabled(true);
mapView.getMapSettings().setZoomWithAnchorEnabled(true);
mapView.getMapSettings().setInertiaRotatingEnabled(true);
mapView.getMapSettings().setInertiaZoomingEnabled(true);
mapView.getMapSettings().setInertiaPanningEnabled(true);
SKVersioningManager.getInstance().setMapUpdateListener(this);
mapView.centerMapOnPosition(new SKCoordinate( -118.123,34.123));
//launchRouteCalculation();
}
It seems that reportNewGPSPosition(this.currentPosition); does not work instantly.
I noticed that if I simply delay the call to centerMapOnCurrentPosition(), the map is centered correctly. There are two work arounds:
-set location manually:
mapView.centerMapOnPosition(new SKCoordinate( currentPosition.getLongitude(), currentPosition.getLatitude()));
-or create a delayed runnable to call to perform the centering at a future time:
android.os.Handler handler = new android.os.Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mapView.centerMapOnCurrentPosition();
mapView.setZoom(10);
}
},100);
note: This issue only becomes evident because of the if statement I put in to only center the map on the first update of location. Another work around would be to put a use a counter and center map on the second time the location is updated.
Also if implementing this with the mentioned if statement, don't forget to consider accuracy; it would be bad to center when the location is not accurate, and not center on a future location update which IS accurate.
I am simulating a car moving on a pre-recorded path on Android maps v2. When I zoom on the path by hand, it works great, but when I move the camera over the path with mMap.animateCamera(), it doesn't load the visible map area, I only get a very pixelated, low quality map. If I touch the screen and move the map or zoom a little, then it loads again this part.
How can I achieve, that it always loads clearly the visible part?
EDIT:
I added an example image: this is what I see when I don't touch the map. After I touch it, it becomes clear (similar to the bottom left part).
EDIT2:
I have an idea, that this is because Google want's to prevent the map to be cached by quickly moving the camera over an area. Is it possible, that this is the cause of this issue? (The map is showing Budapest, Hungary, which part of the map you can not download for offline use...) But here I only want to show the animation and place markers, I only need the visible area to be cached - are there any way to workaround this behaviour?
EDIT3:
The animation code:
new Thread(new Runnable() {
#Override
public void run() {
// ... Calculating and sending new location, in an infinite loop with sleeps for timing
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude())));
}
});
}
}).start();
Finally found a solution. I was able to recreate your problem using the code you provided. I replaced your code with the following and it worked for me.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// ... Calculating and sending new location, in an infinite loop with sleeps for timing
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude())));
}
});
}
}, 0, 2000);
Just remove your code for sleeping and replace the last argument in scheduleAtFixedRate (the 2000) with whatever value you were using for sleeping.
I had the same issue. Since it did not happen when not animating the camera, it had to be something related to that.
Apperently the camera has to be able to finish its operation, before it will update the background/roads etc.
Since my app updates the position every second and the map needs about 2 seconds to complete I end up with pixelated roads and no surroundings at all.
The solution is to use one of overloads of animateCamera:
public final void animateCamera (CameraUpdate update, int durationMs,
GoogleMap.CancelableCallback callback)
Moves the map according to the update with an animation over a
specified duration, and calls an optional callback on completion. See
CameraUpdateFactory for a set of updates.
I used for my case a duration of 900msec, so the animation is done before it receives a new location.
To get the callback to work you need to implement GoogleMap.CancelableCallback to your class. This requires you to add two overrides:
#Override
public void onFinish() {
}
#Override
public void onCancel() {
}
They are not required to get the problem solved, altough you are free to add extra logic there.
The call to update the camera can look like this:
cameraPosition = new CameraPosition.Builder()
.target(current)
.zoom(zoomLevel)
.bearing(bearing)
.tilt(tilt)
.build();
CameraUpdate update = CameraUpdateFactory.newCameraPosition(cameraPosition);
map.animateCamera(update, 900, this);
After long search on how to blink a marker i came up with this code in my project using google maps v2. Here is the code..
MyMarker = map.addMarker(new MarkerOptions().position(current_loc).title(address).snippet(city).
icon(BitmapDescriptorFactory.fromResource(R.drawable.bus4)));
markertimer = new Timer();
markertimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
blinkMarker();
}
});
}
}, 0, 500);
here the blinkMarker method..
private boolean blinkMarker(){
if(marker == true){
current.setVisible(true);
marker = false;
}
else if(marker == false){
current.setVisible(false);
marker = true;
}
return marker;
}
So the above is working fine and the marker is blinking , but my doubt is
will the above code use more memory for blinking?
and i'm using reverse geocoding for getting address, so not able to click the marker when blinking. Please suggest any other way to blink the marker?
Try replacing setVisible with setIcon. When doing that you need to prepare another drawable for icon with the same size as bus4.png, but with all pixels transparent.
Note there is a bug related to setIcon that causes info window to disappear.
As a side note a couple of problems in your code:
Using Timer is wasteful. It uses Thread, which you don't need. Consider using Handler instead.
You (probably) have a memory leak. Timer will not stop working when the Activity is destroyed. You need to cancel it if you don't do that already. If switching to Handler, rember to remove any Runnables or Messages you send.
Usually a Google map is more busy: with many markers. So, you can use Scheduledthreadpoolexecutor with runnable.
Your blinkMarket method could be shorter, like this:
'current.setVisible(!marker)'. I'm affraid that using Timer is not right approach. You can do the same using Handler with postDelayed. If the flashing of marker depends on some condition, that should be repeately checked, than flashing task should not be generated twice.
So in my current application, I want to zoom to a lat/long point, but also use the animateTo (or equivalent) to make sure the screen is properly centered. Currently I'm just doing something like this:
_mapController.animateTo(new GeoPoint(googleLat, googleLng));
// Smooth zoom handler
int zoomLevel = _mapView.getZoomLevel();
int targetZoomLevel = AppConstants.MAP_ZOOM_LEVEL_SWITCH;
long delay = 0;
while (zoomLevel++ < targetZoomLevel) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
_mapController.zoomIn();
}
}, delay);
delay += 350; // Change this to whatever is good on the device
}
This kind of works, but what happens is that my thread starts, BEFORE the 'animate to' finishes, so it zooms in and then 'jumps' to display the correct center geoPoint. Is there a way to smoothly 'drill down' to a certain zoom level, as well as move to a geoPoint at the same time? Similar to how the official Googl eMaps application zooms to an address after you've searched for it is what I'm looking to do.
I would do something like:
_mapController.animateTo(new GeoPoint(googleLat,googleLong), new Runnable() {
public void run()
{
_mapController.zoomIn ();
}
});
This will achieve a pan-then-zoom effect. You can try your same logic inside the runnable to perform multi-step zoomIn's.