i am trying to run a geoquery everytime someone select a place from PlaceAutoComplete fragment and show the markers on the map. It is working fine for the first.When i start the app the icons are are all fine the geoquery is running fine, but when i enter a location second time the app crashes showing an error llegalArgumentException: Unmanaged descriptor below is what i am trying to do.
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
SupportPlaceAutocompleteFragment autocompleteFragment =
(SupportPlaceAutocompleteFragment)
getChildFragmentManager().findFragmentById
(R.id.place_autocomplete_fragment);
autocompleteFragment.setOnPlaceSelectedListener(new
PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
// TODO: Get info about the selected place.
Toast.makeText(getContext(),place.getAddress(),Toast.LENGTH_LONG).show();
Log.i(TAG, "Place: " + place.getName());
Double latitude1 = place.getLatLng().latitude;
Double longitude1 =place.getLatLng().longitude;
LatLng latLng = new LatLng(latitude1,longitude1);
getPeople(latLng); // method to call geofire query
}
#Override
public void onError(Status status) {
// TODO: Handle the error.
Log.i(TAG, "An error occurred: " + status);
}
});
return mMainView;
}
public void getPeople(LatLng latLng1){
mMap.clear();
mMap.addCircle(new CircleOptions()
.center(latLng1)
.radius(2000)
.strokeColor(Color.BLACK)
.fillColor(0x220000FF)
.strokeWidth(1)
);
DatabaseReference ref =
FirebaseDatabase.getInstance().getReference().child("Location");
GeoFire geoFire = new GeoFire(ref);
GeoQuery geoQuery = geoFire.queryAtLocation(new
GeoLocation(latLng1.latitude, latLng1.longitude), 2);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
#Override
public void onKeyEntered(final String key, GeoLocation location) {
UIDLocation.put(key,location);
marker.setIcon(BitmapDescriptorFactory.fromResource
(R.drawable.ic_mapmarker2));
markers.put(key, marker);
for (Map.Entry<String,GeoLocation> entry : UIDLocation.entrySet())
{
final Marker marker = markers.get(entry.getKey());
if (marker != null) {
DatabaseReference mUser =
FirebaseDatabase.getInstance().getReference().child("People")
.child(string);
mUser.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
String display_name =
dataSnapshot.child("name").getValue().toString();
String status =
dataSnapshot.child("status").getValue().toString();
String image =
dataSnapshot.child("image").getValue().toString();
PeopleInfo info = new PeopleInfo();
info.setName(display_name);
info.setStatus(status);
info.setImage(image);
marker.setTag(info);
String iconName = dataSnapshot.child("iconName")
.getValue().toString();
Context context = getContext();
int id = context.getResources().getIdentifier(iconName, "drawable",
context.getPackageName());
String s = String.valueOf(id);
Bitmap icon = BitmapFactory.decodeResource(context.getResources(),id);
marker.setIcon(BitmapDescriptorFactory.fromResource(id));
}
#Override
public void onCancelled(DatabaseError
databaseError) {
}
});
}
}
#Override
public void onMapReady(final GoogleMap googleMap) {
mMap = googleMap;
mUiSettings = mMap.getUiSettings();
mUiSettings.setZoomControlsEnabled(true);
mFusedLocationClient =
LocationServices.getFusedLocationProviderClient(getContext());
Task task= mFusedLocationClient.getLastLocation()
.addOnSuccessListener(getActivity(), new
OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
LatLng latLng = new LatLng(latitude, longitude);
myPosition = new LatLng(latitude, longitude);
markeroptn = new MarkerOptions();
markeroptn.position(myPosition);
markeroptn.title("You are Here");
mMap.moveCamera(CameraUpdateFactory.newLatLng(myPosition));
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(myPosition,10));
getWorkMen(myPosition);
}
}
});
So far what i have learned from the posts on SO that its because the program is trying to set the icon on marker which is already there. I tried clear() map in the begining of getPeople() but still it is showing the same error.It works fine first time. i also tried remove() also but its also not working.
The problem may come from the way you manage the Marker variables. In the code, you store a marker variable as global outside of the method scope. When calling map.clear(), it makes the marker variable invalid and if somehow you still use this variable to set something, it may cause the exception. The same thing happens with the markers Map you use to map key and Marker, it's not being cleared when map.clear().
Try to manage your map elements more carefully, clear each map element dependently and avoid using map.clear().
Suggestion approach:
Create new marker
private void addMarker(String key, LatLng latLng) {
// Clear the current marker before add the new one
if (marker != null) {
marker.remove();
marker = null;
}
// Store new marker to the variable
marker = mMap.addCircle(new CircleOptions()
.center(latLng)
.radius(2000)
.strokeColor(Color.BLACK)
.fillColor(0x220000FF)
.strokeWidth(1)
);
// Add to markers map if needed
markers.put(key, marker);
}
Clear all markers (clear manually every marker variable available, don't use map.clear:
public synchronized void clear() {
// markers is the marker map
for (Marker marker : markers.values()) {
try {
marker.remove();
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
}
// Clear all the marker map
markers.clear();
// Marker is the your global marker variable
marker.remove();
}
Related
I am trying to replace mMpap.SetMyPosition(true); function with my own. I had some success on it and when my custom image for "My Position Icon" is tapped, it moves camera to current location with my custom marker.
Everything works fine on it except whenever "My Position Icon" is tapped, it leaves a copy of marker to that position and moves to current location with a new marker.
I am fairly new to Android Development and looking for some help.
My code inside onCreate(Bundle savedInstanceState) is:
ImageView img = (ImageView) findViewById(R.id.myPostionButton);
img.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
getTheLocation();
}
});
And getTheLocation() is:
if (location != null) {
final double latitude = location.getLatitude();
final double longitude = location.getLongitude();
LatLng latLng = new LatLng(latitude, longitude);
final Marker marker = mMap.addMarker(
new MarkerOptions()
.position(new LatLng(latitude, longitude))
.draggable(true)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker)));
mMap.setTrafficEnabled(true);
mMap.setMinZoomPreference(10.0f);
mMap.setMaxZoomPreference(20.0f);
//mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16.0f),4000 , null);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16.0f));
mMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
#Override
public void onCameraMove() {
LatLng centerOfMap = mMap.getCameraPosition().target;
marker.setPosition(centerOfMap);
}
});
mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
#Override
public void onCameraIdle() {
LatLng centerOfMap = mMap.getCameraPosition().target;
marker.setPosition(centerOfMap);
double latitude = centerOfMap.latitude;
double longitude = centerOfMap.longitude;
Geocoder geocoder = new Geocoder(getApplicationContext());
try {
List<Address> addressList = geocoder.getFromLocation(latitude, longitude, 1);
String str = addressList.get(0).getAddressLine(0) + ", ";
str += addressList.get(0).getSubLocality() + ", ";
str += addressList.get(0).getLocality() + ", ";
str += addressList.get(0).getCountryCode();
mFromAddress.setText(str);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
And onMapReady(GoogleMap googleMap) is:
mMap = googleMap;
getTheLocation();
Please Help.
You can try any one of the following based on your situation:
1. If you have only one marker in map, before adding the new marker, clear the map using mMap.clear();
2. If you have multiple markers then you have to keep your current marker object as member variable mMarker. Then just before adding the new marker you can use mMarker.remove();.
I have previously asked the similar question where I had issue with saving the data in the firebase cloud. I managed to store the latitude & longitude data in the firebase database using following code
#Override
public void onMapReady(GoogleMap map) {
mMap = map;
// Use a custom info window adapter to handle multiple lines of text in the
// info window contents.
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
// Return null here, so that getInfoContents() is called next.
public View getInfoWindow(Marker arg0) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
// Inflate the layouts for the info window, title and snippet.
View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_contents,
(FrameLayout)findViewById(R.id.map), false);
TextView title = ((TextView) infoWindow.findViewById(R.id.title));
title.setText(marker.getTitle());
TextView snippet = ((TextView) infoWindow.findViewById(R.id.snippet));
snippet.setText(marker.getSnippet());
return infoWindow;
}
});
// Turn on the My Location layer and the related control on the map.
updateLocationUI();
// Get the current location of the device and set the position of the map.
getDeviceLocation();
}
// Gets the current location of the device, and positions the map's camera.
private void getDeviceLocation() {
/*
* Request location permission, so that we can get the location of the
* device. The result of the permission request is handled by a callback,
* onRequestPermissionsResult.
*/
if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mLocationPermissionGranted = true;
} else {
ActivityCompat.requestPermissions(this,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
}
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference databaseReference = database.getReference();
Intent intent = getIntent();
callingActivity = intent.getIntExtra( "callingActivity",0 );
//If the map has been called from ScanActivity
if (callingActivity == 1) {
// Get the best and most recent location of the device
if (mLocationPermissionGranted) {
mLastKnownLocation = LocationServices.FusedLocationApi
.getLastLocation( mGoogleApiClient );
scanString = intent.getStringArrayListExtra( "beaconList" );
nameList = intent.getStringArrayListExtra( "nameList" );
addressList = intent.getStringArrayListExtra( "addressList" );
RssiList = intent.getIntegerArrayListExtra( "RssiList" );
for ( int i=0; i < scanString.size(); i++) {
addBeacon.name = nameList.get( i );
addBeacon.address = addressList.get( i );
addBeacon.Rssi = RssiList.get( i );
addBeacon.latitude = mLastKnownLocation.getLatitude();
addBeacon.longitude = mLastKnownLocation.getLongitude();
databaseReference.child( "foo" ).child(addBeacon.address).setValue( addBeacon);
}
}
}
But the problem is when I try to retrieve the location I see is my device's location instead of the saved latlong value in the firebase data base. I have 2 calling activities i.e. 1 is for storing the lat long to firebase and 2 for retrieving it. I can successfully save the value under unique id and update it whereas I am unable to retrieve the latlong. I am using following code for retrieval
else {
DatabaseReference latlong= FirebaseDatabase.getInstance().getReference().child( "foo" ).child( "08:9E:08:B4:57:18" );
mFirebaseDatabase.keepSynced(true);
al ValueEventListener beaconListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
LatLng newLocation = new LatLng(
dataSnapshot.child("latitude").getValue(Long.class),
dataSnapshot.child("longitude").getValue(Long.class));
//LatLng mRetrieved = new LatLng(dataSnapshot.getValue(beacon.class).latitude, dataSnapshot.getValue(beacon.class).longitude);
//mLastKnownLocation.setLatitude( dataSnapshot.getValue(beacon.class).latitude );
// mLastKnownLocation.setLatitude(60.192059);
mMap.addMarker( new MarkerOptions()
.position( newLocation)
.title( dataSnapshot.getKey()));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
databaseReference.addValueEventListener( beaconListener );
Here i am changing the lat long value of 1 particular child name "08:9E:08:B4:57:18" manually in database to check if i can see the marker in the map at that location but it just shows my device's current location.
I can provide further screen shot of my database n the application if required. Thanks in advance. Hope to have some valuable pointers.
Please add this code after adding marker, so that the marker will move to the location which you added
try {
CameraUpdate center = CameraUpdateFactory.newLatLng(new LatLng(lat, lng));
CameraUpdate zoom = CameraUpdateFactory.zoomTo(12);
googleMap.moveCamera(center);
googleMap.animateCamera(zoom);
} catch (Exception e) {
Log.getStackTraceString(e);
}
In PostExecute i have this array name : locations
I print Log for more details like that:
[lat/lng: (18.5159983333333,-72.2916166666667), lat/lng: (18.5363383333333,-72.3231866666667), lat/lng: (18.5076266666667,-72.3164933333333), lat/lng: (18.54138,-72.2920766666667)]
And i try to show all coordinates like that
protected void onPostExecute(Boolean result) {
dialog.dismiss();
for (int i = 0; i < locations.size(); i++)
{
Double latitude = Double.valueOf(locations.get(i).latitude);
Double longitude = Double.valueOf(locations.get(i).longitude);
LatLng lng = new LatLng(latitude,longitude);
map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
map.addMarker(new MarkerOptions()
.position(lng)
.title("Test")
.icon(BitmapDescriptorFactory.fromResource(getResources().getIdentifier("Title", "drawable", getPackageName()))));
}
}
Google map shows blank. How may i resolve it please??
You can only add markers when your map is ready to receive them and that is true when
public void onMapReady(GoogleMap googleMap)
is called.
I will try to get you started with this:
You need to setup some variables:
private GoogleMap mMap;
private boolean isMapReady = false;
private ArrayList<LatLng> myLocations = null;
the ArrayList will contain your locations you get from your AsyncTask
Then you need to get the mapOnReady setup in your onCreate() Methode:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
// What ever else you need
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.mapViewRidesFoundMap);
mapFragment.getMapAsync(this);
}
Now you need to override the onMapReady method:
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Set a boolean flag to let other parts of you code
// know that the map is ready
isMapReady = true;
// If you need to get info from your marker Implement this
//mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
// #Override
// public boolean onMarkerClick(Marker marker) {
// showMarkerInfo(marker);
// return false;
// }
//});
//If you need a click listener add this
// Add implement the method 'onMapClickLocation'
//mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
// #Override
// public void onMapClick(LatLng latLng) {
// onMapClickLocation(latLng);
// }
//});
// call a function to update your locations
updateMapLocations();
}
Within your(!) protected void onPostExecute(Boolean result) add code to fill the myLocations ArrayList
protected void onPostExecute(Boolean result) {
dialog.dismiss();
myLocations = new ArrayList<LatLng>();
for (int i = 0; i < locations.size(); i++)
{
Double latitude = Double.valueOf(locations.get(i).latitude);
Double longitude = Double.valueOf(locations.get(i).longitude);
LatLng lng = new LatLng(latitude,longitude);
myLocations.put(lng);
}
// calls the update method when data is available
this.updateMapLocations();
}
and add a call to updateMapLocations() which could look like this:
private void updateMapLocations(){
// update locations won't continue unless the map is ready
if(!isMapReady) return;
// Zoom into your location !! if you need too
// with a destinationLocation of your choice
// perhaps your first location in you ArrayList
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(destinationLocation, zoomFactor));
// PseudoCode!!
// Add your for Loop
// !!! Check to see if your myLocations ArrayList is null before you continue !!!
// !!! or just add another boolean to you onPostExcecute method
// And add the Markers
//Loop Start
//float hue = BitmapDescriptorFactory.HUE_MAGENTA;
//MarkerOptions markerOptions = setMarker(latLng, hue)
// !!! You need to add your destination loop !!!
//mMap.addMarker(markerOptions);
//Loop end!
}
private MarkerOptions setMarker(LatLng latLng, float hue){
MarkerOptions markerOptions = null;
try {
float markerAlpha = 0.7f;
markerOptions = new MarkerOptions();
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(hue));
markerOptions.position(latLng);
markerOptions.alpha(markerAlpha);
markerOptions.flat(false);
markerOptions.title("What Ever");
markerOptions.snippet("MySnippet");
markerOptions.draggable(false);
markerOptions.zIndex(0.0f);
}
catch (Exception ex){
Log.e(TAG, " setMarker --- " + ex.getMessage());
}
return markerOptions;
}
Notice that updateMapLocations() is called in both your onPostExecute() and the onMapReady() methods. The onPostExecute() might be finished before the onMapReady() is called. So that first when the map is ready the updateMapLocations() will run to completion when data and map are ready.
I wrote this in a text editor - so there will probably be a couple of syntax errors.
I am developing an app which has an activity having map in it. When users open this activity from their devices, their current location coordinates is saved in the Firebase and then are retrieved instantly and a marker is shown on their current location. This procedure is happening successfully.
Here's how I'm retrieving the latitude and longitude from firebase:
acceptingUserReference.child(requestID).child(key).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
final Map<String, String> newAcceptedUser = (Map<String, String>) dataSnapshot.getValue();
nameOfP.add(newAcceptedUser.get("pName"));
cLatP.add(newAcceptedUser.get("cLat").trim());
cLngP.add(newAcceptedUser.get("cLng").trim());
currentLat.add(newAcceptedUser.get("currentLat").trim());
currentLng.add(newAcceptedUser.get("currentLng").trim());
addMarkers();
//Check map is loaded
mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
#Override
public void onMapLoaded() {
mMap.getUiSettings().setZoomControlsEnabled(true);
mMap.getUiSettings().setMapToolbarEnabled(true);
mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
mMap.setMaxZoomPreference(19.0f); mMap.setMyLocationEnabled(true);
}
});
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Here's how:
public void addMarkers() {
mMap.clear();
venueMarker = mMap.addMarker(new MarkerOptions().position(new LatLng(Double.parseDouble(venueLat), Double.parseDouble(venueLng)));
markersList.add(venueMarker);
for (int i = 0; i < nameOfP.size(); i++) {
p = mMap.addMarker(new MarkerOptions().position(new LatLng(Double.valueOf(cLatP.get(i)), Double.valueOf(cLngP.get(i)))).title(nameOfP.get(i).trim()).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
markersList.add(pMarker);
}
}
The problem arises when I the users moves and their location changes. Now, I want to remove the marker from their previous location and show it on their updated current location. For doing this, I'm using LocationRequest to get location and then saving the updated location in Firebase.
Here's how:
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
currentLtAU = mCurrentLocation.getLatitude();
currentLnAU = mCurrentLocation.getLongitude();
aReference.child(rID).child(userID).child("currentLat").setValue(String.valueOf(currentLtAU));
aReference.child(rID).child(userID).child("currentLng").setValue(String.valueOf(currentLnAU));
updateMarkers();
}
Now, to update markers based on this updated location, I'm trying this:
public void updateMarkers() {
mMap.clear();
venueMarker = mMap.addMarker(new MarkerOptions().position(new LatLng(Double.parseDouble(venueLat), Double.parseDouble(venueLng)));
markersList.add(venueMarker);
for (int i = 0; i < nameOfP.size(); i++) {
p = mMap.addMarker(new MarkerOptions().position(new LatLng(Double.valueOf(currentLat.get(i)), Double.valueOf(currentLng.get(i)))).title(nameOfP.get(i).trim()).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
markersList.add(pMarker);
}
}
but on doing this, many markers are getting added and also the app is getting crashed giving this error: java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2 and also addMarkers() gets called everytime.
Please help me to figure out what is going wrong here and how to achieve what I want.
I have implemented Google maps v2 for Android app. My location, marker everything is showing fine, but when I am on move OnMylocationChange is called and marker is updated, but I have to scroll up or down as the view of my location goes off the map.
How do I update my map to scroll with my current location? Like Google Maps App.
#Override
public void onMyLocationChange(Location location)
{
if (markermylocation != null)
{
markermylocation.remove();
}
curlat = location.getLatitude();
curlong = location.getLongitude();
myLocation(curlat, curlong, username, imageURL, ZOOMVALUE);
}
private void myLocation(double lat, double lng, String name, String url, float zoom)
{
if(firsttime == 1)
{
LatLng ll = new LatLng(lat,lng);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(ll, zoom);
googleMap.animateCamera(update);
firsttime = 0;
}
final String uname = name;
curlat = lat;
curlong = lng;
Picasso.with(getActivity()).load(url).resize(120, 120).transform(transformation).into(new Target()
{
#Override
public void onBitmapFailed(Drawable arg0)
{
markerOptionsmylocaiton = new MarkerOptions().position(new LatLng(curlat, curlong)).icon(BitmapDescriptorFactory.fromResource(R.drawable.profilepic)).title(uname).anchor(0.5f, 1f);
markermylocation = googleMap.addMarker(markerOptionsmylocaiton);
}
#Override
public void onBitmapLoaded(Bitmap b, LoadedFrom arg1)
{
bitmapMarkermylocation = BitmapDescriptorFactory.fromBitmap(b);
if(b != null)
{
markerOptionsmylocaiton = new MarkerOptions().position(new LatLng(curlat, curlong)).icon(bitmapMarkermylocation).title(uname).anchor(0.5f, 1f);
}
else
{
markerOptionsmylocaiton = new MarkerOptions().position(new LatLng(curlat, curlong)).icon(BitmapDescriptorFactory.fromResource(R.drawable.profilepic)).title(uname).anchor(0.5f, 1f);
}
markermylocation = googleMap.addMarker(markerOptionsmylocaiton);
}
#Override
public void onPrepareLoad(Drawable arg0)
{
}
});
}
Thanks!
I think you just have to remove the if (firsttime == 1) conditional, then the map should recenter whenever your location is updated.
LatLng ll = new LatLng(lat,lng);
CameraUpdate update = null;
if(firsttime == 1) {
update = CameraUpdateFactory.newLatLngZoom(ll, zoom);
firsttime = 0;
} else {
update = CameraUpdateFactory.newLatLng(ll);
}
googleMap.animateCamera(update);
is there a reason you have that in there?
as mentioned in spec:
CameraUpdateFactory is a class containing methods for creating CameraUpdate objects that change a map's camera. To modify the map's camera, call animateCamera(CameraUpdate), animateCamera(CameraUpdate, GoogleMap.CancelableCallback) or moveCamera(CameraUpdate), using a CameraUpdate object created with this class.
read more
so when you are implementing this :
markermylocation = googleMap.addMarker(markerOptionsmylocaiton);
take care of camera move with this methods:
// Showing the current location in Google Map
googleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
// Zoom in the Google Map
googleMap.animateCamera(CameraUpdateFactory.zoomTo(15));