Vista de mapa siguiente usuario – Funcionalidad de tipo MyLocationOverlay para Android Maps API v2

Cambié a v2 de Maps para Android, y estoy tratando de puerto sobre la siguiente funcionalidad:

Con MyLocationOverlay puedo mostrar la ubicación actual de los dispositivos (Blue Dot). Cuando la ubicación del usuario cambia y el punto llega al borde del área visible, el mapa se anima para que el punto se convierta en el centro de la vista, en tiempo real.

En v2, estoy utilizando SupportMapFragment con getMap (). SetMyLocationEnabled (true). La ubicación actual aparece como un punto azul (flecha), pero cuando el dispositivo cambia de ubicación, la vista de mapa no cambia y el punto finalmente sale de la vista.

¿Algunas ideas?

ACTUALIZACIÓN : Google presentó el nuevo LocationClient y LocationClient asociado (la interfaz OnMyLocationChangeListener está ahora obsoleta). Así que ahora el centrado automático de la cámara es una tarea trivial.


Aunque spotdog ya respondió a la pregunta que quería compartir mi propio ejemplo, que espero que ayude a otros principiantes Android a entender mejor lo que se necesita para hacer un LocationSource personalizado para la capa de mi ubicación. Esperamos que usted encontrará que el código está bien documentado / comentado.

 public class PlaceMapFragment extends SupportMapFragment { // Note that this may be null if the Google Play services APK is not available. private GoogleMap mMap; protected PlaceActivity activity; private FollowMeLocationSource followMeLocationSource; private Context mContext; /* We need the Context in order to get a reference to the Location Manager * (when instantiating this fragment from your activity use: * PlaceMapFragment mapFragment = new PlaceMapFragment(this); ) */ public PlaceMapFragment(Context context) { this.mContext = context; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); activity = (PlaceActivity)getActivity(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // creates our custom LocationSource and initializes some of its members followMeLocationSource = new FollowMeLocationSource(); /* We can't be guaranteed that the map is available because Google Play services might not be available. * (un-comment the following line when using this code in a FragmentActivity / Activity * to try get a reference to the map here !) */ //setUpMapIfNeeded(); } @Override public void onResume() { super.onResume(); /* We query for the best Location Provider everytime this fragment is displayed * just in case a better provider might have become available since we last displayed it */ followMeLocationSource.getBestAvailableProvider(); // Get a reference to the map/GoogleMap object setUpMapIfNeeded(); /* Enable the my-location layer (this causes our LocationSource to be automatically activated.) * While enabled, the my-location layer continuously draws an indication of a user's * current location and bearing, and displays UI controls that allow a user to interact * with their location (for example, to enable or disable camera tracking of their location and bearing).*/ mMap.setMyLocationEnabled(true); } @Override public void onPause() { /* Disable the my-location layer (this causes our LocationSource to be automatically deactivated.) */ mMap.setMyLocationEnabled(false); super.onPause(); } /** * Sets up the map if it is possible to do so (ie, the Google Play services APK is correctly * installed) and the map has not already been instantiated. This will ensure that we only ever * manipulate the map once when it {@link #mMap} is not null. * <p> * If it isn't installed {@link SupportMapFragment} (and {@link com.google.android.gms.maps.MapView * MapView}) will show a prompt for the user to install/update the Google Play services APK on their device. */ private void setUpMapIfNeeded() { // Do a null check to confirm that we have not already instantiated the map. if (mMap == null) { mMap = getMap(); // Check if we were successful in obtaining the map. if (mMap != null) { // The Map is verified. It is now safe to manipulate the map: // Replace the (default) location source of the my-location layer with our custom LocationSource mMap.setLocationSource(followMeLocationSource); // Set default zoom mMap.moveCamera(CameraUpdateFactory.zoomTo(15f)); } } } /* Our custom LocationSource. * We register this class to receive location updates from the Location Manager * and for that reason we need to also implement the LocationListener interface. */ private class FollowMeLocationSource implements LocationSource, LocationListener { private OnLocationChangedListener mListener; private LocationManager locationManager; private final Criteria criteria = new Criteria(); private String bestAvailableProvider; /* Updates are restricted to one every 10 seconds, and only when * movement of more than 10 meters has been detected.*/ private final int minTime = 10000; // minimum time interval between location updates, in milliseconds private final int minDistance = 10; // minimum distance between location updates, in meters private FollowMeLocationSource() { // Get reference to Location Manager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); // Specify Location Provider criteria criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_LOW); criteria.setAltitudeRequired(true); criteria.setBearingRequired(true); criteria.setSpeedRequired(true); criteria.setCostAllowed(true); } private void getBestAvailableProvider() { /* The preffered way of specifying the location provider (eg GPS, NETWORK) to use * is to ask the Location Manager for the one that best satisfies our criteria. * By passing the 'true' boolean we ask for the best available (enabled) provider. */ bestAvailableProvider = locationManager.getBestProvider(criteria, true); } /* Activates this provider. This provider will notify the supplied listener * periodically, until you call deactivate(). * This method is automatically invoked by enabling my-location layer. */ @Override public void activate(OnLocationChangedListener listener) { // We need to keep a reference to my-location layer's listener so we can push forward // location updates to it when we receive them from Location Manager. mListener = listener; // Request location updates from Location Manager if (bestAvailableProvider != null) { locationManager.requestLocationUpdates(bestAvailableProvider, minTime, minDistance, this); } else { // (Display a message/dialog) No Location Providers currently available. } } /* Deactivates this provider. * This method is automatically invoked by disabling my-location layer. */ @Override public void deactivate() { // Remove location updates from Location Manager locationManager.removeUpdates(this); mListener = null; } @Override public void onLocationChanged(Location location) { /* Push location updates to the registered listener.. * (this ensures that my-location layer will set the blue dot at the new/received location) */ if (mListener != null) { mListener.onLocationChanged(location); } /* ..and Animate camera to center on that location ! * (the reason for we created this custom Location Source !) */ mMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude()))); } @Override public void onStatusChanged(String s, int i, Bundle bundle) { } @Override public void onProviderEnabled(String s) { } @Override public void onProviderDisabled(String s) { } } } 

Debe agregar un LocationSource a su GoogleMap y responder a eventos onLocationChanged. Aquí hay una clase simple que pide la ubicación del usuario, luego espera hasta que la ubicación del usuario esté disponible y anima el mapa para centrarse en su ubicación.

 public class MyLocationMapFragmentActivity extends FragmentActivity implements LocationListener, LocationSource { /** * Note that this may be null if the Google Play services APK is not available. */ private GoogleMap mMap; private OnLocationChangedListener mListener; private LocationManager locationManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.basic_map); locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); if(locationManager != null) { boolean gpsIsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); boolean networkIsEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); if(gpsIsEnabled) { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000L, 10F, this); } else if(networkIsEnabled) { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000L, 10F, this); } else { //Show an error dialog that GPS is disabled. } } else { //Show a generic error dialog since LocationManager is null for some reason } setUpMapIfNeeded(); } @Override public void onPause() { if(locationManager != null) { locationManager.removeUpdates(this); } super.onPause(); } @Override public void onResume() { super.onResume(); setUpMapIfNeeded(); if(locationManager != null) { mMap.setMyLocationEnabled(true); } } /** * Sets up the map if it is possible to do so (ie, the Google Play services APK is correctly * installed) and the map has not already been instantiated.. This will ensure that we only ever * call {@link #setUpMap()} once when {@link #mMap} is not null. * <p> * If it isn't installed {@link SupportMapFragment} (and * {@link com.google.android.gms.maps.MapView * MapView}) will show a prompt for the user to install/update the Google Play services APK on * their device. * <p> * A user can return to this Activity after following the prompt and correctly * installing/updating/enabling the Google Play services. Since the Activity may not have been * completely destroyed during this process (it is likely that it would only be stopped or * paused), {@link #onCreate(Bundle)} may not be called again so we should call this method in * {@link #onResume()} to guarantee that it will be called. */ private void setUpMapIfNeeded() { // Do a null check to confirm that we have not already instantiated the map. if (mMap == null) { // Try to obtain the map from the SupportMapFragment. mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.basicMap)).getMap(); // Check if we were successful in obtaining the map. if (mMap != null) { setUpMap(); } //This is how you register the LocationSource mMap.setLocationSource(this); } } /** * This is where we can add markers or lines, add listeners or move the camera. In this case, we * just add a marker near Africa. * <p> * This should only be called once and when we are sure that {@link #mMap} is not null. */ private void setUpMap() { mMap.setMyLocationEnabled(true); } @Override public void activate(OnLocationChangedListener listener) { mListener = listener; } @Override public void deactivate() { mListener = null; } @Override public void onLocationChanged(Location location) { if( mListener != null ) { mListener.onLocationChanged( location ); //Move the camera to the user's location once it's available! mMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude()))); } } @Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub Toast.makeText(this, "provider disabled", Toast.LENGTH_SHORT).show(); } @Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub Toast.makeText(this, "provider enabled", Toast.LENGTH_SHORT).show(); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub Toast.makeText(this, "status changed", Toast.LENGTH_SHORT).show(); } } 

Esto debe seguir al usuario y seguir centrando el mapa en su ubicación a medida que cambia – si desea centralizar sólo el mapa en el usuario cuando se van "fuera de la pantalla", entonces usted podría comprobar para ver si la ubicación del usuario está dentro Los límites visibles del mapa

 @Override public void onLocationChanged(Location location) { if( mListener != null ) { mListener.onLocationChanged( location ); LatLngBounds bounds = this.mMap.getProjection().getVisibleRegion().latLngBounds; if(!bounds.contains(new LatLng(location.getLatitude(), location.getLongitude()))) { //Move the camera to the user's location if they are off-screen! mMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude()))); } } } 

Aquí hay una breve reseña sobre el tema: Google Maps Android API V2 MyLocation UbicaciónSource y manejo de eventos

ACTUALIZAR

He editado cómo obtengo la ubicación del usuario (vea el código locationManager en onCreate). He encontrado que el uso de los métodos "getBestProvider" no son confiables y simplemente no funcionan en varios dispositivos. Yo tenía varios usuarios se quejan de que sus dispositivos nunca encontrar su ubicación, no importa lo relajado que hice los criterios. Parece que la recolección manual de GPS o Network funciona universalmente.

Sólo use OnMyLocationChangeListener , anule el método public void onMyLocationChange(Location location) . Usa GoogleMap.setOnMyLocationChangeListener(your listener) para registrar a tu oyente.

 public void onMyLocationChange(Location location) { changeMapLocation(location); } private void changeMapLocation(Location location) { LatLng latlong = new LatLng(location.getLatitude(), location.getLongitude()); map.moveCamera(CameraUpdateFactory.newLatLngZoom(latlong, 15)); // Zoom in, animating the camera. map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null); } 
  • Cómo girar un marcador en OSMDroid para Android?
  • Android: mapa personalizado sin conexión utilizando una imagen
  • Clustering marcadores en android mapas v2
  • Reaccionar biblioteca de mapas nativos
  • Navegación con Android: ¿cómo podría pasar toda la ruta (no sólo el punto final) al software de navegación externo?
  • Determinar la ubicación del usuario en los mapas de osm
  • OsmDroid y MapQuest: ¿Cómo puedo usar los mosaicos JPEG?
  • Google Maps Android en el país
  • Android Explicit Intent lanza el error NoClassDefFound
  • Cómo emular la ubicación del GPS en el simulador de Android-x86 (VirtualBox)?
  • Mover MapFragment (SurfaceView) hace que el fondo negro parpadee
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.