webentwicklung-frage-antwort-db.com.de

Kartenansicht nach Benutzer - MyLocationOverlay-Funktion für Android Maps API v2

Ich habe zu v2 von Maps für Android gewechselt und versuche, die folgenden Funktionen zu portieren:

Mit MyLocationOverlay kann ich den aktuellen Standort der Geräte anzeigen (blauer Punkt). Wenn sich der Standort des Benutzers ändert und der Punkt den Rand des sichtbaren Bereichs erreicht, wird die Karte animiert, sodass der Punkt in Echtzeit zum Mittelpunkt der Ansicht wird.

In Version 2 verwende ich SupportMapFragment mit getMap (). SetMyLocationEnabled (true). Der aktuelle Standort wird als blauer Punkt (Pfeil) angezeigt. Wenn das Gerät den Standort ändert, wird die Kartenansicht jedoch nicht verschoben, und der Punkt verlässt die Ansicht.

Irgendwelche Ideen?

15
oviroa

UPDATE: Google hat den neuen LocationClientNAME_ und den zugehörigen LocationListenerNAME_ (eingeführt (die OnMyLocationChangeListenername__-Schnittstelle ist nun veraltet). Die automatische Zentrierung der Kamera ist jetzt eine triviale Aufgabe.


Obwohl spotdog bereits auf die Frage geantwortet hat, wollte ich mein eigenes Beispiel teilen, von dem ich hoffe, dass es Android-Anfängern hilft, besser zu verstehen, was erforderlich ist, um einen benutzerdefinierten LocationSourcefür die my-location-Ebene zu erstellen. Hoffentlich werden Sie feststellen, dass der Code gut dokumentiert/kommentiert ist.

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 (i.e., 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 (e.g. 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) {

        }
    }

}
14
Nevermore

Sie müssen Ihrer GoogleMap eine LocationSource hinzufügen und auf onLocationChanged-Ereignisse reagieren. Hier ist eine einfache Klasse, die nach dem Standort des Benutzers fragt, dann wartet, bis der Standort des Benutzers verfügbar ist, und die Karte animiert, sich auf ihren Standort zu zentrieren.

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 (i.e., 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();
}
}

Dies sollte dem Benutzer folgen und die Karte immer auf ihren Standort zentrieren, wenn sie geändert wird. Wenn Sie die Karte nur auf den Benutzer zentrieren möchten, wenn sie den Bildschirm verlassen, können Sie prüfen, ob sich der Standort des Benutzers in der Nähe befindet die sichtbaren Grenzen der Karte

@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())));
        }
    }
}

Hier eine kurze Zusammenfassung des Themas: Google Maps Android API V2 MyLocation LocationQuelle und Ereignisbehandlung

UPDATE

Ich habe bearbeitet, wie ich den Standort des Benutzers erhalte (siehe locationManager-Code in onCreate). Ich habe festgestellt, dass die Verwendung der "getBestProvider" -Methoden nicht zuverlässig ist und einfach nicht auf mehreren Geräten funktioniert. Ich hatte mehrere Benutzer beschwert, dass ihre Geräte niemals ihren Standort finden würden, egal wie locker ich die Kriterien aufgestellt habe. Es scheint, dass das manuelle Auswählen von GPS oder Netzwerk universell funktioniert.

24
DiscDev

Verwenden Sie einfach OnMyLocationChangeListener und überschreiben Sie die Methode public void onMyLocationChange(Location location). Verwenden Sie GoogleMap.setOnMyLocationChangeListener(your listener), um Ihren Listener zu registrieren.

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);
    }
0