【问题标题】:How to get My Location changed event with Google Maps android API v2?如何使用 Google Maps android API v2 获取我的位置更改事件?
【发布时间】:2012-11-24 10:03:38
【问题描述】:

如何使用Google Maps android API v2 获取“我的位置”更改事件?

v1 中,您可以执行以下操作以处理位置更改事件:

public class MyLocationOverlay extends com.google.android.maps.MyLocationOverlay {

    /**
     * Listener
     */
    public interface Listener {
        void onLocationChanged(android.location.Location location);
    }

    private Listener listener;

    public MyLocationOverlay(Context context, MapView mapView, Listener listener) {
        super(context, mapView);

        this.listener = listener;
    }

    @Override
    public synchronized void onLocationChanged(Location location) {
        super.onLocationChanged(location);

        // fire listener
        if (listener != null)
            listener.onLocationChanged(location);
    }
}

【问题讨论】:

  • 似乎唯一的解决方案是使用自己的LocationSource实现

标签: android google-maps geolocation


【解决方案1】:

更新:Google 引入了新的LocationClient 和关联的LocationListenerOnMyLocationChangeListener 接口现已弃用)。


您可以通过为 my-location 层创建自定义 LocationSource 来实现此目的。下面是一个自动将相机定位在当前位置(“我的位置”)的示例,类似于 Google Maps Android API v1 中MyLocationOverlay 提供的功能。

所以你可以简单地替换这行代码

mMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude())));

当位置改变时你需要执行的任何功能。

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) {

        }
    }

}

【讨论】:

  • OnMyLocationChangeListener 何时包含在 Google Play 服务中?
  • @mahemadhi 上个月。您可以查看release notes
  • 是的,想想它的 Google Play Services 修订版 5
  • 2016年读到这个,你能告诉我如何使用新的LocationClient
【解决方案2】:

【讨论】:

  • 这很严重,因为第一次更新当前位置应该动画到用户的位置(例如第一次位置已过期)。现在,我需要用处理程序创建一个循环来检查位置是否改变了吗?真的吗?
  • Google 更新了 API。下面的人给出了一个可行的解决方案。我认为他应该得到“检查”
  • @brainmurphy1:题外话,但“下面的人”在 stackoverflow 上是一个错误的概念,因为帖子的排序可能会通过 up-/downvotes 改变:) 您可以在输入 @. 你的 cmets
  • @muetzenflo 很高兴知道。我应该说“@Nevermore 的解决方案。”
【解决方案3】:

我遇到了同样的问题......我现在的解决方案:

创建一个线程,要求 Handler 多次获取位置。您需要使用 Handler,因为 getMyLocation 方法只能从 GUI Thread 调用:

private class MyLocationThread extends Thread{
        @Override
        public void run() {
            int loops = 0;
            // we give the location search a minute 
            while(loops < 60){
                // we have to try it over a handler, because getMyLocation() has to be called from GUI Thread -_-
                _getMyLocationHandler.sendEmptyMessage(0);
                if(isInterrupted()){
                    return;
                }
                // take a short nap before next try
                try {Thread.sleep(1000);} catch(Exception e){}
                loops++;
            }

        }
    }

这是处理程序的作用:

private Handler _getMyLocationHandler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            if(getMap().isMyLocationEnabled() && getMap().getMyLocation() != null){
                _locationWatcher.interrupt();
                drawCurrentImagePositions();
            }
        }
    };

【讨论】:

  • 它只能检测到第一个变化(当它变为非空时)。后来,它无法检测到变化。您甚至可以记住最后的位置,但您仍然会有 1 秒的延迟(Thread.sleep(1000);),此时可以更改位置并且不会通知您。
  • 是的,我的意图是只捕捉第一个变化。但是由于谷歌修补了监听器,因此不再需要整个解决方法......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多