I am trying to get the LatLngBounds from the Visible Region on the device's screen after my Google map has been initialized. However I only receive a 0 values. My guess is that the map has not actually been loaded, even after OnMapReady has been called. I've looked all over for a better way of checking for map initialization and found nothing. How do I ensure I receive the correct data?
INITIALIZE MAP
public void initMap(){
MapFragment map = (MapFragment) getFragmentManager().findFragmentById(R.id.mapFragment);
map.getMapAsync(this);
}
ON MAP READY CALLBACK
#Override
public void onMapReady(GoogleMap googleMap) {
try {
if (googleMap != null) {
mGoogleMap = googleMap;
mGoogleMap.setOnMarkerClickListener(this);
mGoogleMap.setOnCameraChangeListener(this);
mGoogleMap.setOnMapClickListener(this);
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
search();
}
} catch (Exception exception) {
mUtility.getThemedAlert(this,
getResources().getString(R.string.error_google_maps),
getResources().getString(R.string.unable_build_google_maps)).show();
}
}
GET BOUNDS
public void search() {
LatLngBounds bounds = mGoogleMap.getProjection().getVisibleRegion().latLngBounds;
Log.e("TEST", bounds.toString());
}
LOG OUTPUT
E/TESTīš LatLngBounds{southwest=lat/lng: (0.0,0.0), northeast=lat/lng: (0.0,0.0)}
OnMapLoaded function helps. Thank you.
Here is my code,
map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
#Override
public void onMapLoaded() {
invokeApi();
}
});
Related
I want to register a OnMarkerClickListener to a GoogleMap:
implement the GoogleMap.OnMarkerClickListener interface
register listener via GoogleMap.setOnMarkerClickListener(this)
but when I click on a marker the callback onMarkerClick() is never called. For test purposes I also implemented OnMapLongClickListener and it works perfectly well.
public class ShowCoords extends FragmentActivity implements
OnMapReadyCallback,
LocationListener,
GoogleMap.OnCameraMoveListener,
GoogleMap.OnCameraMoveStartedListener,
GoogleMap.OnMyLocationButtonClickListener,
GoogleMap.OnMyLocationClickListener,
GoogleMap.OnMarkerClickListener,
GoogleMap.OnMapLongClickListener {
private GoogleMap mMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show_coords);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setZoomControlsEnabled(true);
mMap.getUiSettings().setScrollGesturesEnabled(true);
mMap.getUiSettings().setCompassEnabled(true);
mMap.getUiSettings().setMapToolbarEnabled(false);
if (gpsPermission()) {
mMap.setMyLocationEnabled(true);
}
mMap.setOnMyLocationButtonClickListener(this);
mMap.setOnMyLocationClickListener(this);
mMap.setOnCameraMoveStartedListener(this);
mMap.setOnCameraMoveListener(this);
mMap.setOnMarkerClickListener(this);
mMap.setOnMapLongClickListener(this);
if (displayFormat.equals(getString(R.string.heatmapValue))) {
// display markers as heatmap
} else if (displayFormat.equals(getString(R.string.clusterValue))) {
// diplay markers as cluster
mClusterManager = new ClusterManager<>(this, mMap);
mMap.setOnCameraIdleListener(mClusterManager);
// this causes the problem
mMap.setOnMarkerClickListener(mClusterManager);
for (LatLng p : coords) {
mClusterManager.addItem(new MyClusterItem(p));
}
} else {
Log.w(TAG, "onMapReady: coords still null, nothing to display");
}
//just for testing
mMap.addMarker(new MarkerOptions().position(new LatLng(51.866404, 12.643411)));
}
#Override
public boolean onMarkerClick(Marker marker) {
Log.i(TAG, "onMarkerClick");
return true;
}
#Override
public void onMapLongClick(LatLng latLng) {
Log.i(TAG, "onMapLongClick");
}
// removed other callbacks
}
Any ideas, whats going wrong?
I got it. When I display the markers as a cluster (via Google Maps Android Marker Clustering Utility) the clustermanager registers as OnMarkerClickListener and the registration of my listener get lost. As a workaround, I omit the clustermanager registration and pass the click event on the clustermanager by myself.
I am aware that in Play Services, getMap() is depreciated, and is replaced by getMapAsync().
But I am not sure how to use getMapAsync(). I found other questions similar to this -- however, in my code, I am not sure what to implement in my getMapAsync(). I think it is supposed to be a callback method, but I am not sure.
Could someone please put the correct code in, and tell me what I am doing wrong?
public class FindParty extends AppCompatActivity {
static final LatLng Durban = new LatLng(-29.858680, 31.021840);
private GoogleMap googleMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_find_party);
try{
if (googleMap == null) {
googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMapAsync();
}
googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
googleMap.setTrafficEnabled(true);
googleMap.setIndoorEnabled(true);
googleMap.setBuildingsEnabled(true);
googleMap.getUiSettings().setZoomControlsEnabled(true);
final Marker marker_Durban = googleMap.addMarker(new MarkerOptions()
.position(Durban)
.snippet("Durban, KwaZulu-Natal, South Africa")
.title("Durban"));
googleMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker marker) {
if (marker.getTitle().equals("Durban")) {
Intent intent = new Intent(FindParty.this, Party.class);
intent.putExtra("message", "Durban");
startActivity(intent);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
your class need to implements OnMapReadyCallback
public class FindParty extends AppCompatActivity implements OnMapReadyCallback {
static final LatLng Durban = new LatLng(-29.858680, 31.021840);
private GoogleMap googleMap;
MapFragment mapFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_find_party);
try {
if (googleMap == null) {
mapFragment = ((MapFragment) getFragmentManager().findFragmentById(R.id.map));
mapFragment.getMapAsync(this);
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onMapReady(GoogleMap map) {
googleMap = map;
googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
googleMap.setTrafficEnabled(true);
googleMap.setIndoorEnabled(true);
googleMap.setBuildingsEnabled(true);
googleMap.getUiSettings().setZoomControlsEnabled(true);
final Marker marker_Durban = googleMap.addMarker(new MarkerOptions()
.position(Durban)
.snippet("Durban, KwaZulu-Natal, South Africa")
.title("Durban"));
googleMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker marker) {
if (marker.getTitle().equals("Durban")) {
Intent intent = new Intent(FindParty.this, Party.class);
intent.putExtra("message", "Durban");
startActivity(intent);
}
}
});
}
}
You are right, getMapAsync() is based on callback, please see belowe example and move your map options settings to callback method:
Example
getMapAsync() { it.isTrafficEnabled = false }
The better way I found to understand the use of getMapAsync was to create a new project in Android Studio and use the template of google maps activity instead of an empty activity.
Hope help others with the same difficulty.
i'm using google maps in my android app. Everything is fine but when i have no GPS service enabled i show a snackbar message to enable. When i enable GPS and turn back in my Fragment der map dosen't return to my location automaticly only when i press the location button.
I tried to solve the problem by using a thread in my update method but nothing. changed. Sometimes it works but sometimes isn't good enough.
my onCreate:
public void init(){
gps = new GPSTracker();
gps.init(mActivity,mActivity);
if (!gps.canGetLocation()) {
gps.showSettingsAlert(mActivity,rootView);
}else {
initMap();
}
my initMap
private void initMap(){
try {
MapsInitializer.initialize(mActivity.getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
mMapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap mMap) {
googleMap = mMap;
if (ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
googleMap.setMyLocationEnabled(true);
}
moveSearchCircle(new LatLng(gps.getLatitude(), gps.getLongitude()));
updateMapPosition();
googleMap.setIndoorEnabled(true);
addMarker();
}
});
}
updateMapPosition
private void updateMapPosition(){
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(gps.getLatitude(), gps.getLongitude()), 15));
}
onResume
#Override
public void onResume() {
super.onResume();
init();
}
Maybe gps.getLatitude(), gps.getLongitude() returns zero values, and focus of your map's camera trying to set to this place.
Usually, get device location operation takes some time and you should do this asynchronously.
So, please, check your GPSTracker class and find async methods, or see this tutorial.
So I have the following things that are working properly:
I have a map fragment and I have markers on my map. Using .setRetainInstance on my map fragment does exactly what I want, on rotate it keeps the user zoomed position and keeps the markers on their place. The only thing that I want to do now is to make the initial screen of the app to move the camera to a exact location and zoom level. I am doing that with the initialLocation method which if added in the onMapReady does what its supposed to. The problem is that once I add this method inside onMapReady the setRetainInstance is not working anymore, on each rotation the map resets to the initialLocation position. As u will probably realize from my code I am just learning this and I have read a lot of tutorials, but I cannot manage to make it right. Here is part of the code so you can have an idea of what I am talking about. I guess I have to add some sort of conditions in order for this to work. Any suggestions will be appreciated.
private static final double
TOULOUSE_LAT = 43.604346,
TOULOUSE_LNG = 1.443760;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SupportMapFragment mapFragment = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
if (savedInstanceState == null){
mapTypeSelected = GoogleMap.MAP_TYPE_NORMAL;
mapFragment.setRetainInstance(true);
} else {
mapTypeSelected = savedInstanceState.getInt("the_map_type", GoogleMap.MAP_TYPE_NORMAL);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
initialLocation(TOULOUSE_LAT,TOULOUSE_LNG, 12);
mMap.setMapType(mapTypeSelected);
addMarkers2Map();// method for adding markers and a lot of other stuff...
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("the_map_type", mapTypeSelected);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
savedInstanceState.get("the_map_type");
}
private void initialLocation(double lat, double lng, float zoom){
LatLng latLng = new LatLng(lat, lng );
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(latLng, zoom);
mMap.moveCamera(update);
}
}
Try adding a member variable similar to this:
Boolean mSetCameraPosition;
Then in onCreate() set the value of mSetCameraPosition before calling getMapAsync():
if (savedInstanceState == null) {
mapTypeSelected = GoogleMap.MAP_TYPE_NORMAL;
mapFragment.setRetainInstance(true);
mSetCameraPosition = true;
}
else {
mapTypeSelected = savedInstanceState.getInt("the_map_type", GoogleMap.MAP_TYPE_NORMAL);
mSetCameraPosition = false;
}
mapFragment.getMapAsync(this);
In onMapReady() use mSetCameraPosition:
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if (mSetCameraPosition) {
initialLocation(TOULOUSE_LAT,TOULOUSE_LNG, 12);
}
mMap.setMapType(mapTypeSelected);
addMarkers2Map(); // method for adding markers and a lot of other stuff...
}
Is it possible to change the zoom level as soon as the map is ready? When I open the app it shows the map and the blue dot for my location. However, the zoom level is the default 3. How can I change this? I know how to do it when the 'MyLocationButton'is clicked but not when the app starts.
This is my class
public class MainPhoneActivity extends FragmentActivity implements ConnectionCallbacks, OnConnectionFailedListener, LocationSource, LocationListener, OnMyLocationButtonClickListener, OnMapReadyCallback{
private GoogleApiClient mGoogleApiClient;
private OnLocationChangedListener mMapLocationListener = null;
// location accuracy settings
private static final LocationRequest REQUEST = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_phone);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.mapView);
mapFragment.getMapAsync(this);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
#Override
protected void onResume() {
super.onResume();
mGoogleApiClient.connect();
}
#Override
public void onPause() {
super.onPause();
mGoogleApiClient.disconnect();
}
#Override
public void onMapReady(GoogleMap map) {
map.setLocationSource(this);
map.setMyLocationEnabled(true);
map.setOnMyLocationButtonClickListener(this);
}
public void showMyLocation(View view) {
if (mGoogleApiClient.isConnected()) {
String msg = "Location = "
+ LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onLocationChanged(Location location) {
if (mMapLocationListener != null) {
mMapLocationListener.onLocationChanged(location);
}
}
#Override
public void onConnected(Bundle connectionHint) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, REQUEST,this);
}
#Override
public void onConnectionSuspended(int cause) {
// Do nothing
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Do nothing
}
#Override
public boolean onMyLocationButtonClick() {
return false;
}
#Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mMapLocationListener = onLocationChangedListener;
}
#Override
public void deactivate() {
mMapLocationListener = null;
}
}
You can set zoom level like following:
map.animateCamera(CameraUpdateFactory.newLatLngZoom(point,15));
Where point is your LatLng position. In this way you can center the map in that point with given zoom level.
Complete method:
#Override
public void onMapReady(GoogleMap map) {
map.setLocationSource(this);
map.setMyLocationEnabled(true);
map.setOnMyLocationButtonClickListener(this);
//newLatLngZoom(LatLng , ZoomLevel) -> choose your zoom level
// and change my 'point' with yours
map.animateCamera(CameraUpdateFactory.newLatLngZoom(point,15));
}
EDIT:
If you want to get the dot coords, you can try this:
Location loc = map.getMyLocation();
LatLng point = new LatLng(loc.getlatitude() , loc.getLongitude());
and use that point as center.
Complete method:
#Override
public void onMapReady(GoogleMap map) {
map.setLocationSource(this);
map.setMyLocationEnabled(true);
map.setOnMyLocationButtonClickListener(this);
Location loc = map.getMyLocation();
if(loc != null){
LatLng point = new LatLng(loc.getLatitude() , loc.getLongitude());
map.animateCamera(CameraUpdateFactory.newLatLngZoom(point,15));
}
}
This could cause a NullPointerException beacuse loc could be null.
OTHER SOLUTION
If you want to get only first time the coordinates, you should work in onLocationChanged, using a boolean variable to set first call.
Declare it CRDS_CALL = false;
#Override
public void onLocationChanged(Location location) {
if (mMapLocationListener != null) {
mMapLocationListener.onLocationChanged(location);
if(!CRDS_CALL){
LatLng point = new LatLng(location.getLatitude(), location.getLognitude());
map.animateCamera(CameraUpdateFactory.newLatLngZoom(point,15));
CRDS_CALL = true;
}
}
}
In this answer i use map, but you have to use your mapFragment, but if you want to use it in other methods over onCreate, you have to declare outside of it.
Add this just before the onCreate
SupportMapFragment mapFragment;
And inside it, use it like follwing:
mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.mapView);
mapFragment.getMapAsync(this);
In that way, you can use mapFragment in other methods
Solution
The solution was to do everything #MikeKeepsOnShine said but remove the
Location loc = map.getMyLocation();
LatLng point = new LatLng(loc.getLatitude() , loc.getLongitude());
map.animateCamera(CameraUpdateFactory.newLatLngZoom(point,15));
part from onMapReady. Works absolutely perfectly now!
You should use this. And you should put this request in onMapReady() callback. Something like this:
#Override
public void onMapReady(GoogleMap map) {
map.setLocationSource(this);
map.setMyLocationEnabled(true);
map.setOnMyLocationButtonClickListener(this);
map.animateCamera(CameraUpdateFactory.zoomTo(14), 2000, null);
}
you have already done the new "MapAsync" way so you are one step forward to the result.
In order to zoom, you can use the animateCamera method for googleMap object to zoom to a specific location:
https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap.html#animateCamera(com.google.android.gms.maps.CameraUpdate)
for example, a zoomin:
map.animateCamera(CameraUpdateFactory.zoomIn());
or if you already know "where":
map.animateCamera(CameraUpdateFactory.newLatLngZoom(knownlocation,17));
and you will be very close to the location.
If you need to do at the first "locationUpdate" you should keep a flag to false and set to true the first time you receive a location, at that time you perform the zoom to location.
EDIT: If you want to zoom only the first time, where you receive location updates (which is not really clear from your code), you can do, assuming you have a class variable like:
private boolean FIRST_TIME = true;
the following code:
if(FIRST_TIME){
myMap.animateCamera(CameraUpdateFactory.newLatLngZoom(location,17));
FIRST_TIME = false;
}
The best option is to remove the listener but it seems you use location updates as "blue dot" updates.
What worked for me was:
mMap.setMinZoomPreference(6.0f);
mMap.setMaxZoomPreference(20.0f);
You can modify the zoom preference values to your taste.