I am new to android development and was working on an app which requires google map activity. Problem I am facing is that when I am trying to pan(or scroll) through the map I am immediately respawned to my current location which I set initially. A little help would be wonderful as I am stuck at this point and unable to find a solution. Here is the code:-
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMapsBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // Obtain the SupportMapFragment and get notified when the map is ready to be used. SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; mMap.getUiSettings().setScrollGesturesEnabled(true); locationManager=(LocationManager)this.getSystemService(Context.LOCATION_SERVICE); locationListener=new LocationListener() { @Override public void onLocationChanged(@NonNull Location location) { centerOnMap(location,"Your Location"); } }; if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},1); } else{ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,locationListener); Location lastKnownLocation=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); centerOnMap(lastKnownLocation,"Your Location"); } } public void centerOnMap(Location location,String address) { LatLng userLocation = new LatLng(location.getLatitude(),location.getLongitude()); mMap.addMarker(new MarkerOptions().position(userLocation).title(address)); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 15)); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull @org.jetbrains.annotations.NotNull String[] permissions, @NonNull @org.jetbrains.annotations.NotNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED) { if(ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION)==PackageManager.PERMISSION_GRANTED){ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,locationListener); } } }
}
Advertisement
Answer
The one requirement that you likely have but not stated is:
When the
lastLocation
becomes available and the user has not moved the map then center the map on the location. If the user has already moved the map then do not center the map. In either case, add a marker at the user’s location.
Before getting too far along it must be noted that Google Maps provides a
feature similar to what you are trying to achieve, though you’d still have to “move camera”. The marker is a blue-ball and not the typical marker. See myMap.setMyLocationEnabled(true)
. That’s it! Do this when you have gotten map permissions.
But in the event you don’t want to use that then here are the simple changes you need.
Remember that the LocationManager
getLastKnownLocation
can return
null if the device does not have one (yet). So I’d recommend one small
change a bit unrelated – just let the location listener do all the work and get rid of this one special case:
// this is where you initially check permissions and have them. else{ locationManager.requestLocationUpdates (LocationManager.GPS_PROVIDER,0,0,locationListener); // Here I removed the last location centering and let the // location listener always handle it. }
So this opens the possibility that the user could be interacting with map and finally the last location arrives. I understand this to be the issue you are trying to address.
(As an aside, it seems to me you are mixing the use of the android.location.LocationManager
with
the FusedLocationProviderApi
(com.google.android.gms.location) so I couldn’t get your
code to compile due to incompatible LocationListener
s.
Unfortunately, Google Maps has two LocationListener
classes so
to be certain you’d have to include your imports to understand further.)
Anyways…
When the map is first ready (onMapReady
) the camera of the map is
centered at (0,0)
. You can get the cameras target position (center)
at any time using LatLng tgtCtr = mMap.getCameraPosition().target;
.
Oddly enough it is not straightforward to know whether the user has interacted with the map in any way: scrolling events generate camera changes while touch events generate a separate event. Camera changes cannot be used exclusively because your code or the user could just zoom which is not moving the map. You could go this route but for the purposes of this answer, to keep things simple, the camera target is used.
Declare a class instance variable (same area where you define mMap
):
LatLng tgtCtr;
So in your onMapReady
after assigning mMap
do:
tgtCtr = mMap.getCameraPosition().target;
So assume your code exists as you posted (it’s pretty close) then these changes may help:
// This change simply restricts centering of the map on location // update to only when user has not moved the map (scrolled). @Override public void onLocationChanged(@NonNull Location location) { LatLng currentCtr = mMap.getCamaraPosition().target; // This is not the ideal check since `double` comparisons // should account for epsilon but in this case of (0,0) it should work. // Alternatively you could compute the distance of current // center to (0,0) and then use an epsilon: // see `com.google.maps.android.SphericalUtil.computeDistanceBetween`. if (currentCtr.latitude == 0 && currentCtr.longitude == 0) { centerOnMap(location,"Your Location"); } }
It also seems like a good idea to save the marker which was added for user’s location – this is optional but may come in handy to prevent multiple markers from being added at that one location:
// Define a class instance variable Marker myLocMarker = nulll; // and then in centerOnMap public void centerOnMap(Location location, String address) { // ... other code if (myLocMarker == null) { myLocMarker = mMap.addMarker(new MarkerOptions().position(userLocation).title(address)); } // ... more code }
So really the only difficulty in this is figuring out “has the user moved the map.” In this case, based on the initial requirement you would not want to move the map.