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.
Related
I want to achieve a marker animation such as GIF animation. I got two images which should be blinking simultaneously. I found nothing which can acheive this in android. I am trying to do is , creating a handler which run every 1 second , and I am trying to set icon for marker. But it doesnt work. Please guide me in right direction.
my code as of now is as follows.
Handler handler = new Handler();
Boolean marker_color_bool = true;
//adding marker and sending the marker instance to marker_animation() method where handler is called.
MarkerOptions marker = new MarkerOptions()
.title(delivery_center_name)
.snippet("This is the " + delivery_center_name + " location")
.position(location)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.red_marker));
google_map.addMarker(marker);
marker_animation(marker);
marker_animation() method
private final int ONE_SECONDS = 1000;
public void marker_animation(final MarkerOptions marker ) {
handler.postDelayed(new Runnable() {
public void run() {
Log.e("running",""+marker_color_bool);
if(marker_color_bool == true)
{
marker.icon(BitmapDescriptorFactory.fromResource(R.drawable.green_marker));
marker_color_bool = false;
}
else
{
marker.icon(BitmapDescriptorFactory.fromResource(R.drawable.red_marker));
marker_color_bool = true;
}
handler.postDelayed(this, ONE_SECONDS);
}
}, ONE_SECONDS);
}
this approach doesnt work..Please help me what I am doing wrong.
Please help me what I am doing wrong
You are modifying an object that is no longer being used. Once addMarker() is called, the MarkerOptions object has no further meaning, yet this is what you are modifying via your postDelayed() logic.
(BTW, you don't need a Handler, as postDelayed() is available on any View)
addMarker() returns a Marker. You will need to work with that Marker to affect your changes, via setIcon().
Also, since your bitmaps are not changing, I suggest caching your two BitmapDescriptor objects, rather than re-creating them on every pass.
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);
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.
Are there some kind events for animateTo() is finished in android's MapView?
I don't mean manual scrolls, I mean animateTo()-calls from my code or animateTo()-calls causing by changing myLocation if myLocation is enabled?
Thank you
Yes, there is an animateTo that takes a Runnable parameter. You can use this in this manner:
mapController.animateTo(geoPoint,
new Runnable() {
#Override
public void run() {
// your code
}
});