在 Android 上获取用户当前位置的最简单、最可靠的方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3145089/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:55:10  来源:igfitidea点击:

What is the simplest and most robust way to get the user's current location on Android?

androidgeolocationlocationlatitude-longitude

提问by emmby

The LocationManagerAPI on Android seems like it's a bit of a pain to use for an application that only needs an occasional and rough approximation of the user's location.

LocationManagerAndroid 上的API 对于只需要偶尔粗略估计用户位置的应用程序来说似乎有点麻烦。

The app I'm working on isn't really a location app per se, but it does need to get the user's location in order to display a list of nearby businesses. It doesn't need to worry about if the user is moving around or anything like that.

我正在开发的应用程序本身并不是真正的位置应用程序,但它确实需要获取用户的位置才能显示附近企业的列表。它不需要担心用户是否在四处走动或类似的事情。

Here's what I'd like to do:

这是我想要做的:

  1. Show the user a list of nearby locations.
  2. Preload the user's location so that by the time I need it in ActivityX, it will be available.
  3. I don't particularly care about accuracy or frequency of update. Just grabbing one location is sufficient as long as it's not way off. Maybe if I want to be fancy I'll update the location once every few mins or so, but it's not a huge priority.
  4. Work for any device as long as it has either a GPS or a Network Location provider.
  1. 向用户显示附近位置的列表。
  2. 预加载用户的位置,以便我在ActivityX 中需要它时,它将可用。
  3. 我并不特别关心更新的准确性或频率。只要不远,只需抓住一个位置就足够了。也许如果我想花哨的话,我会每隔几分钟左右更新一次位置,但这不是一个很大的优先事项。
  4. 适用于任何设备,只要它有 GPS 或网络位置提供程序。

It seems like it shouldn't be that hard, but it appears to me that I have to spin up two different location providers (GPS and NETWORK) and manage each's lifecycle. Not only that, but I have to duplicate the same code in multiple activities to satisfy #2. I've tried using getBestProvider()in the past to cut the solution down to just using one location provider, but that seems to only give you the best "theoretical" provider rather than the provider that's actually going to give you the best results.

看起来它不应该那么难,但在我看来,我必须启动两个不同的位置提供程序(GPS 和 NETWORK)并管理每个的生命周期。不仅如此,我还必须在多个活动中复制相同的代码才能满足 #2。我过去曾尝试getBestProvider()将解决方案缩减为仅使用一个位置提供商,但这似乎只能为您提供最佳的“理论”提供商,而不是实际上会给您带来最佳结果的提供商。

Is there a simpler way to accomplish this?

有没有更简单的方法来实现这一点?

回答by Fedor

Here's what I do:

这是我所做的:

  1. First of all I check what providers are enabled. Some may be disabled on the device, some may be disabled in application manifest.
  2. If any provider is available I start location listeners and timeout timer. It's 20 seconds in my example, may not be enough for GPS so you can enlarge it.
  3. If I get update from location listener I use the provided value. I stop listeners and timer.
  4. If I don't get any updates and timer elapses I have to use last known values.
  5. I grab last known values from available providers and choose the most recent of them.
  1. 首先,我检查启用了哪些提供程序。有些可能在设备上被禁用,有些可能在应用程序清单中被禁用。
  2. 如果有任何提供者可用,我会启动位置侦听器和超时计时器。在我的例子中是 20 秒,对于 GPS 来说可能不够,所以你可以放大它。
  3. 如果我从位置侦听器获得更新,我将使用提供的值。我停止听众和计时器。
  4. 如果我没有收到任何更新并且计时器已过,我必须使用最后一个已知值。
  5. 我从可用的提供者那里获取最新的已知值并选择最新的值。

Here's how I use my class:

这是我如何使用我的课程:

LocationResult locationResult = new LocationResult(){
    @Override
    public void gotLocation(Location location){
        //Got the location!
    }
};
MyLocation myLocation = new MyLocation();
myLocation.getLocation(this, locationResult);

And here's MyLocation class:

这是 MyLocation 类:

import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

public class MyLocation {
    Timer timer1;
    LocationManager lm;
    LocationResult locationResult;
    boolean gps_enabled=false;
    boolean network_enabled=false;

    public boolean getLocation(Context context, LocationResult result)
    {
        //I use LocationResult callback class to pass location value from MyLocation to user code.
        locationResult=result;
        if(lm==null)
            lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

        //exceptions will be thrown if provider is not permitted.
        try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){}
        try{network_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){}

        //don't start listeners if no provider is enabled
        if(!gps_enabled && !network_enabled)
            return false;

        if(gps_enabled)
            lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
        if(network_enabled)
            lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
        timer1=new Timer();
        timer1.schedule(new GetLastLocation(), 20000);
        return true;
    }

    LocationListener locationListenerGps = new LocationListener() {
        public void onLocationChanged(Location location) {
            timer1.cancel();
            locationResult.gotLocation(location);
            lm.removeUpdates(this);
            lm.removeUpdates(locationListenerNetwork);
        }
        public void onProviderDisabled(String provider) {}
        public void onProviderEnabled(String provider) {}
        public void onStatusChanged(String provider, int status, Bundle extras) {}
    };

    LocationListener locationListenerNetwork = new LocationListener() {
        public void onLocationChanged(Location location) {
            timer1.cancel();
            locationResult.gotLocation(location);
            lm.removeUpdates(this);
            lm.removeUpdates(locationListenerGps);
        }
        public void onProviderDisabled(String provider) {}
        public void onProviderEnabled(String provider) {}
        public void onStatusChanged(String provider, int status, Bundle extras) {}
    };

    class GetLastLocation extends TimerTask {
        @Override
        public void run() {
             lm.removeUpdates(locationListenerGps);
             lm.removeUpdates(locationListenerNetwork);

             Location net_loc=null, gps_loc=null;
             if(gps_enabled)
                 gps_loc=lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
             if(network_enabled)
                 net_loc=lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

             //if there are both values use the latest one
             if(gps_loc!=null && net_loc!=null){
                 if(gps_loc.getTime()>net_loc.getTime())
                     locationResult.gotLocation(gps_loc);
                 else
                     locationResult.gotLocation(net_loc);
                 return;
             }

             if(gps_loc!=null){
                 locationResult.gotLocation(gps_loc);
                 return;
             }
             if(net_loc!=null){
                 locationResult.gotLocation(net_loc);
                 return;
             }
             locationResult.gotLocation(null);
        }
    }

    public static abstract class LocationResult{
        public abstract void gotLocation(Location location);
    }
}

Somebody may also want to modify my logic. For example if you get update from Network provider don't stop listeners but continue waiting. GPS gives more accurate data so it's worth waiting for it. If timer elapses and you've got update from Network but not from GPS then you can use value provided from Network.

有人可能还想修改我的逻辑。例如,如果您从网络提供商处获得更新,请不要停止侦听器而是继续等待。GPS 提供更准确的数据,因此值得等待。如果计时器已过并且您已从网络获得更新但未从 GPS 获得更新,则您可以使用网络提供的值。

One more approach is to use LocationClient http://developer.android.com/training/location/retrieve-current.html. But it requires Google Play Services apk to be installed on user device.

另一种方法是使用 LocationClient http://developer.android.com/training/location/retrieve-current.html。但它需要在用户设备上安装 Google Play Services apk。

回答by wormhit

After searching for best implementation how to get best precise user location I managed to combine all the best methods and come up with following class:

在搜索了如何获得最佳精确用户位置的最佳实现之后,我设法结合了所有最佳方法并提出了以下课程:

/**
 * Retrieve accurate location from GPS or network services. 
 * 
 *
 * Class usage example:
 * 
 * public void onCreate(Bundle savedInstanceState) {
 *      ...
 *      my_location = new MyLocation();
 *      my_location.init(main.this, locationResult);
 * }
 * 
 * 
 * public LocationResult locationResult = new LocationResult(){
 *      @Override
 *      public void gotLocation(final Location location){
 *          // do something
 *          location.getLongitude();
 *          location.getLatitude();
 *      }
 *  };
 */
class MyLocation{

    /**
     * If GPS is enabled. 
     * Use minimal connected satellites count.
     */
    private static final int min_gps_sat_count = 5;

    /**
     * Iteration step time.
     */
    private static final int iteration_timeout_step = 500;

    LocationResult locationResult;
    private Location bestLocation = null;
    private Handler handler = new Handler();
    private LocationManager myLocationManager; 
    public Context context;

    private boolean gps_enabled = false;

    private int counts    = 0;
    private int sat_count = 0;

    private Runnable showTime = new Runnable() {

         public void run() {
            boolean stop = false;
            counts++;
            System.println("counts=" + counts);

            //if timeout (1 min) exceeded, stop tying
            if(counts > 120){
                stop = true;
            }

            //update last best location
            bestLocation = getLocation(context);

            //if location is not ready or don`t exists, try again
            if(bestLocation == null && gps_enabled){
                System.println("BestLocation not ready, continue to wait");
                handler.postDelayed(this, iteration_timeout_step);
            }else{
                //if best location is known, calculate if we need to continue to look for better location
                //if gps is enabled and min satellites count has not been connected or min check count is smaller then 4 (2 sec)  
                if(stop == false && !needToStop()){
                    System.println("Connected " + sat_count + " sattelites. continue waiting..");
                    handler.postDelayed(this, iteration_timeout_step);
                }else{
                    System.println("#########################################");
                    System.println("BestLocation finded return result to main. sat_count=" + sat_count);
                    System.println("#########################################");

                    // removing all updates and listeners
                    myLocationManager.removeUpdates(gpsLocationListener);
                    myLocationManager.removeUpdates(networkLocationListener);    
                    myLocationManager.removeGpsStatusListener(gpsStatusListener);
                    sat_count = 0;

                    // send best location to locationResult
                    locationResult.gotLocation(bestLocation);
                }
            }
         }
    };

    /**
     * Determine if continue to try to find best location
     */
    private Boolean needToStop(){

        if(!gps_enabled){
                          return true;
                     }
          else if(counts <= 4){
                return false;
            }
            if(sat_count < min_gps_sat_count){
                //if 20-25 sec and 3 satellites found then stop
                if(counts >= 40 && sat_count >= 3){
                    return true;
                }
                return false;
            }
        }
        return true;
    }

    /**
     * Best location abstract result class
     */
    public static abstract class LocationResult{
         public abstract void gotLocation(Location location);
     }

    /**
     * Initialize starting values and starting best location listeners
     * 
     * @param Context ctx
     * @param LocationResult result
     */
    public void init(Context ctx, LocationResult result){
        context = ctx;
        locationResult = result;

        myLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

        gps_enabled = (Boolean) myLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

        bestLocation = null;
        counts = 0;

        // turning on location updates
        myLocationManager.requestLocationUpdates("network", 0, 0, networkLocationListener);
        myLocationManager.requestLocationUpdates("gps", 0, 0, gpsLocationListener);
        myLocationManager.addGpsStatusListener(gpsStatusListener);

        // starting best location finder loop
        handler.postDelayed(showTime, iteration_timeout_step);
    }

    /**
     * GpsStatus listener. OnChainged counts connected satellites count.
     */
    public final GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
        public void onGpsStatusChanged(int event) {

             if(event == GpsStatus.GPS_EVENT_SATELLITE_STATUS){
                try {
                    // Check number of satellites in list to determine fix state
                     GpsStatus status = myLocationManager.getGpsStatus(null);
                     Iterable<GpsSatellite>satellites = status.getSatellites();

                     sat_count = 0;

                     Iterator<GpsSatellite>satI = satellites.iterator();
                     while(satI.hasNext()) {
                         GpsSatellite satellite = satI.next();
                         System.println("Satellite: snr=" + satellite.getSnr() + ", elevation=" + satellite.getElevation());                         
                         sat_count++;
                     }
                } catch (Exception e) {
                    e.printStackTrace();
                    sat_count = min_gps_sat_count + 1;
                }

                 System.println("#### sat_count = " + sat_count);
             }
         }
    };

    /**
     * Gps location listener.
     */
    public final LocationListener gpsLocationListener = new LocationListener(){
        @Override
         public void onLocationChanged(Location location){

        }
         public void onProviderDisabled(String provider){}
         public void onProviderEnabled(String provider){}
         public void onStatusChanged(String provider, int status, Bundle extras){}
    }; 

    /**
     * Network location listener.
     */
    public final LocationListener networkLocationListener = new LocationListener(){
        @Override
         public void onLocationChanged(Location location){

        }
         public void onProviderDisabled(String provider){}
         public void onProviderEnabled(String provider){}
         public void onStatusChanged(String provider, int status, Bundle extras){}
    }; 


    /**
     * Returns best location using LocationManager.getBestProvider()
     * 
     * @param context
     * @return Location|null
     */
    public static Location getLocation(Context context){
        System.println("getLocation()");

        // fetch last known location and update it
        try {
            LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

            Criteria criteria = new Criteria();
            criteria.setAccuracy(Criteria.ACCURACY_FINE);
             criteria.setAltitudeRequired(false);
             criteria.setBearingRequired(false);
             criteria.setCostAllowed(true);
             String strLocationProvider = lm.getBestProvider(criteria, true);

             System.println("strLocationProvider=" + strLocationProvider);
             Location location = lm.getLastKnownLocation(strLocationProvider);
             if(location != null){
                return location;
             }
             return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

This class tries to connect to min_gps_sat_countsatellites if GPS is enabled. Else returns LocationManager.getBestProvider()location. Check the code!

min_gps_sat_count如果启用 GPS,该类将尝试连接到卫星。否则返回LocationManager.getBestProvider()位置。检查代码!

回答by differenziale

With Fedor's solution I've experienced multiple execution of the callback gotLocation. It seems to be due to a race conditionin the overridden LocationListener.onLocationChangedmethod, when gotLocation method is 'long enough'. I'm not sure, but I guess removeUpdatesprevents the enqueueing of new messages in the Looper queue, but it doesn't remove those already enqueued but not yet consumed. Hence the race condition.

使用 Fedor 的解决方案,我经历了多次执行回调gotLocation。这似乎是由于覆盖方法中的竞争条件LocationListener.onLocationChanged,当 gotLocation 方法是'long enough'。我不确定,但我想removeUpdates阻止了 Looper 队列中新消息的入队,但它不会删除那些已经入队但尚未消耗的消息。因此,竞争条件。

To reduce the probability of this wrong behavior it's possible to call removeUpdates before firing the onLocationChanged event, but still we have the race condition.

为了减少这种错误行为的可能性,可以在触发 onLocationChanged 事件之前调用 removeUpdates,但我们仍然有竞争条件。

The best solution I found is to replace requestLocationUpdateswith requestSingleUpdate.

我找到的最佳解决方案是替换requestLocationUpdatesrequestSingleUpdate.

This is my version, based on Fedor's solution, using an Handler to send a message to the looper thread:

这是我的版本,基于 Fedor 的解决方案,使用 Handler 向 Looper 线程发送消息:

public class LocationResolver {
    private Timer timer;
    private LocationManager locationManager;
    private LocationResult locationResult;
    private boolean gpsEnabled = false;
    private boolean networkEnabled = false;
    private Handler locationTimeoutHandler;

    private final Callback locationTimeoutCallback = new Callback() {
        public boolean handleMessage(Message msg) {
            locationTimeoutFunc();
            return true;
        }

        private void locationTimeoutFunc() {   
            locationManager.removeUpdates(locationListenerGps);
            locationManager.removeUpdates(locationListenerNetwork);

            Location networkLocation = null, gpsLocation = null;
            if (gpsEnabled)
                gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            if (networkEnabled)
                networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

            // if there are both values use the latest one
            if (gpsLocation != null && networkLocation != null) {
                if (gpsLocation.getTime() > networkLocation.getTime())
                    locationResult.gotLocation(gpsLocation);
                else
                    locationResult.gotLocation(networkLocation);
                return;
            }

            if (gpsLocation != null) {
                locationResult.gotLocation(gpsLocation);
                return;
            }
            if (networkLocation != null) {
                locationResult.gotLocation(networkLocation);
                return;
            }
            locationResult.gotLocation(null);           
        }
    };
    private final LocationListener locationListenerGps = new LocationListener() {
        public void onLocationChanged(Location location) {              
            timer.cancel();
            locationResult.gotLocation(location);
            locationManager.removeUpdates(this);
            locationManager.removeUpdates(locationListenerNetwork);
        }

        public void onProviderDisabled(String provider) {
        }

        public void onProviderEnabled(String provider) {
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    };
    private final LocationListener locationListenerNetwork = new LocationListener() {
        public void onLocationChanged(Location location) {    
            timer.cancel(); 
            locationResult.gotLocation(location);
            locationManager.removeUpdates(this);
            locationManager.removeUpdates(locationListenerGps);
        }

        public void onProviderDisabled(String provider) {
        }

        public void onProviderEnabled(String provider) {
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    };

    public void prepare() {
        locationTimeoutHandler = new Handler(locationTimeoutCallback);
    }

    public synchronized boolean getLocation(Context context, LocationResult result, int maxMillisToWait) {
        locationResult = result;
        if (locationManager == null)
            locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

        // exceptions will be thrown if provider is not permitted.
        try {
            gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        } catch (Exception ex) {
        }
        try {
            networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        } catch (Exception ex) {
        }

        // don't start listeners if no provider is enabled
        if (!gpsEnabled && !networkEnabled)
            return false;

        if (gpsEnabled)
            locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, locationListenerGps, Looper.myLooper());
            //locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
        if (networkEnabled)
            locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, locationListenerNetwork, Looper.myLooper());
            //locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);

        timer = new Timer();
        timer.schedule(new GetLastLocationTask(), maxMillisToWait);
        return true;
    }

    private class GetLastLocationTask extends TimerTask {
        @Override
        public void run() { 
            locationTimeoutHandler.sendEmptyMessage(0);
        }
    }

    public static abstract class LocationResult {
        public abstract void gotLocation(Location location);
    }
}

I use this class from a customized looper thread, like the following one:

我从自定义的 Looper 线程使用这个类,如下所示:

public class LocationGetter {
    private final Context context;
    private Location location = null;
    private final Object gotLocationLock = new Object();
    private final LocationResult locationResult = new LocationResult() {            
        @Override
        public void gotLocation(Location location) {
            synchronized (gotLocationLock) {
                LocationGetter.this.location = location;
                gotLocationLock.notifyAll();
                Looper.myLooper().quit();
            }
        }
    };

    public LocationGetter(Context context) {
        if (context == null)
            throw new IllegalArgumentException("context == null");

        this.context = context;
    }

    public synchronized Coordinates getLocation(int maxWaitingTime, int updateTimeout) {
        try {
            final int updateTimeoutPar = updateTimeout;
            synchronized (gotLocationLock) {            
                new Thread() {
                    public void run() {
                        Looper.prepare();
                        LocationResolver locationResolver = new LocationResolver();
                        locationResolver.prepare();
                        locationResolver.getLocation(context, locationResult, updateTimeoutPar);
                        Looper.loop();
                    }
                }.start();

                gotLocationLock.wait(maxWaitingTime);
            }
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        if (location != null)
            coordinates = new Coordinates(location.getLatitude(), location.getLongitude());
        else
            coordinates = Coordinates.UNDEFINED;
        return coordinates; 
    }
}

where Coordinates is a simple class with two properties: latitude and longitude.

其中 Coordinates 是一个具有两个属性的简单类:纬度和经度。

回答by swiftBoy

I have created small application with step by step description to gets current locations GPS co-ordinates.

我创建了带有分步描述的小应用程序,以获取当前位置 GPS 坐标。

enter image description here

在此处输入图片说明

Complete example source code in below URL:

以下 URL 中的完整示例源代码:



Get Current Location coordinates , City name - in Android

获取当前位置坐标,城市名称 - 在 Android 中



See How it works :

看看它怎么运作 :

  • All we need to do is add this permission in manifest file

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">  
    </uses-permission>
    
  • and create LocationManager instance like this

    LocationManager locationManager = (LocationManager) 
                                      getSystemService(Context.LOCATION_SERVICE);
    
  • Check GPS is enabled or not

  • then implement LocationListener and Get Coordinates

    LocationListener locationListener = new MyLocationListener();  
    locationManager.requestLocationUpdates(  
    LocationManager.GPS_PROVIDER, 5000, 10, locationListener);
    
  • here is the sample code to do

  • 我们需要做的就是在清单文件中添加这个权限

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">  
    </uses-permission>
    
  • 并像这样创建 LocationManager 实例

    LocationManager locationManager = (LocationManager) 
                                      getSystemService(Context.LOCATION_SERVICE);
    
  • 检查 GPS 是否启用

  • 然后实现 LocationListener 并获取坐标

    LocationListener locationListener = new MyLocationListener();  
    locationManager.requestLocationUpdates(  
    LocationManager.GPS_PROVIDER, 5000, 10, locationListener);
    
  • 这是要执行的示例代码



/*----------Listener class to get coordinates ------------- */
private class MyLocationListener implements LocationListener {

    @Override
    public void onLocationChanged(Location loc) {
        editLocation.setText("");
        pb.setVisibility(View.INVISIBLE);
        Toast.makeText(
            getBaseContext(),
            "Location changed: Lat: " + loc.getLatitude() + " Lng: "
                + loc.getLongitude(), Toast.LENGTH_SHORT).show();
        String longitude = "Longitude: " + loc.getLongitude();
        Log.v(TAG, longitude);
        String latitude = "Latitude: " + loc.getLatitude();
        Log.v(TAG, latitude);
        /*-------to get City-Name from coordinates -------- */
        String cityName = null;
        Geocoder gcd = new Geocoder(getBaseContext(), Locale.getDefault());
        List<Address> addresses;
        try {
            addresses = gcd.getFromLocation(loc.getLatitude(),
                loc.getLongitude(), 1);
            if (addresses.size() > 0)
                System.out.println(addresses.get(0).getLocality());
            cityName = addresses.get(0).getLocality();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String s = longitude + "\n" + latitude + "\n\nMy Current City is: "
            + cityName;
        editLocation.setText(s);
    }

    @Override
    public void onProviderDisabled(String provider) {}

    @Override
    public void onProviderEnabled(String provider) {}

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {}
}

回答by Robby Pond

You could always just use LocationManager.getLastKnownLocation()but like it says it could be out of date.

你总是可以只使用LocationManager.getLastKnownLocation()但就像它说的那样可能已经过时了。

And a simple way to get a general location could be registering for the network (usually pretty fast).

获取一般位置的一种简单方法可能是注册网络(通常很快)。

LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(
     LocationManager.NETWORK_PROVIDER, 1000, 1000, this);

and then doing

然后做

locationManager.removeUpdates(this);

in the onLocationChanged()method of the listener.

onLocationChanged()侦听器的方法中。

回答by Parsania Hardik

I have written detailed tutorial covering current locationhere on demonuts.com.You can find more description here and also you can download whole demo source code for better understanding.

我在deviluts.com上写了涵盖当前位置的详细教程。您可以在此处找到更多说明,也可以下载整个演示源代码以更好地理解。

There are already many answers there but I want to show latest way to get location using Google API, so new programmers can use new method:

那里已经有很多答案,但我想展示使用 Google API 获取位置的最新方法,因此新程序员可以使用新方法:

First of all, put this in gradle file

首先,把它放在gradle文件中

compile 'com.google.android.gms:play-services:8.4.0'

then implement necessary interfaces

然后实现必要的接口

public class MainActivity  extends BaseActivitiy implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener

declare instances

声明实例

  private GoogleApiClient mGoogleApiClient;
  private Location mLocation;
  private LocationManager locationManager;
  private LocationRequest mLocationRequest;

put this in onCreate()

把这个放进去 onCreate()

 mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

At last, override necessary methods

最后,覆盖必要的方法

 @Override
    public void onConnected(Bundle bundle) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        if(mLocation == null){
            startLocationUpdates();
        }
        if (mLocation != null) {
            double latitude = mLocation.getLatitude();
            double longitude = mLocation.getLongitude();
        } else {
            // Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show();
        }
    }

    protected void startLocationUpdates() {
        // Create the location request
        mLocationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(UPDATE_INTERVAL)
                .setFastestInterval(FASTEST_INTERVAL);
        // Request location updates
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
                mLocationRequest, this);
        Log.d("reque", "--->>>>");
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.i(TAG, "Connection Suspended");
        mGoogleApiClient.connect();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode());
    }

    @Override
    public void onStart() {
        super.onStart();
        mGoogleApiClient.connect();
    }

    @Override
    public void onStop() {
        super.onStop();
        if (mGoogleApiClient.isConnected()) {
            mGoogleApiClient.disconnect();
        }
    }
    @Override
    public void onLocationChanged(Location location) {

    }

Don't forget to start GPS in your device before running app.

在运行应用程序之前,不要忘记在您的设备中启动 GPS。

回答by Jhon

Actualy we can use the two providers(GPS & NETWORK). And they just share a public listener:

实际上,我们可以使用两个提供商(GPS 和网络)。他们只是共享一个公共听众:

locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10 * 1000, (float) 10.0, listener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 90 * 1000, (float) 10.0, listener);

This is necessary because the OnLocationChanged()method always need to be called in time.

这是必要的,因为该OnLocationChanged()方法总是需要及时调用。

回答by npinti

I am not sure if the Location-Based Servicescan get the location from other infrastructures other than GPS, but according to that article, it does seem possible:

我不确定基于位置的服务是否可以从 GPS 以外的其他基础设施获取位置,但根据那篇文章,这似乎是可能的:

Applications can call on any of several types of positioning methods.

Using the mobile phone network: The current cell ID can be used to identify the Base Transceiver Station (BTS) that the device is communicating with and the location of that BTS. Clearly, the accuracy of this method depends on the size of the cell, and can be quite inaccurate. A GSM cell may be anywhere from 2 to 20 kilometers in diameter. Other techniques used along with cell ID can achieve accuracy within 150 meters.

Using satellites: The Global Positioning System (GPS), controlled by the US Department of Defense, uses a constellation of 24 satellites orbiting the earth. GPS determines the device's position by calculating differences in the times signals from different satellites take to reach the receiver. GPS signals are encoded, so the mobile device must be equipped with a GPS receiver. GPS is potentially the most accurate method (between 4 and 40 meters if the GPS receiver has a clear view of the sky), but it has some drawbacks: The extra hardware can be costly, consumes battery while in use, and requires some warm-up after a cold start to get an initial fix on visible satellites. It also suffers from "canyon effects" in cities, where satellite visibility is intermittent.

Using short-range positioning beacons: In relatively small areas, such as a single building, a local area network can provide locations along with other services. For example, appropriately equipped devices can use Bluetooth for short-range positioning.

应用程序可以调用多种类型的定位方法中的任何一种。

使用移动电话网络:当前的小区 ID 可用于识别设备正在与之通信的基站 (BTS) 以及该 BTS 的位置。显然,此方法的准确性取决于单元格的大小,并且可能非常不准确。GSM 蜂窝的直径可能为 2 到 20 公里。与小区 ID 一起使用的其他技术可以达到 150 米以内的精度。

使用卫星:由美国国防部控制的全球定位系统 (GPS) 使用一个由 24 颗环绕地球运行的卫星组成的星座。GPS 通过计算来自不同卫星的信号到达接收器所需的时间差异来确定设备的位置。GPS 信号经过编码,因此移动设备必须配备 GPS 接收器。GPS 可能是最准确的方法(如果 GPS 接收器可以清楚地看到天空,则在 4 到 40 米之间),但它有一些缺点:额外的硬件可能很昂贵,使用时会消耗电池,并且需要一些温暖的在冷启动后启动,以初步修复可见卫星。在卫星能见度时断时续的城市中,它还受到“峡谷效应”的影响。

使用短程定位信标:在相对较小的区域,例如单个建筑物,局域网可以提供位置以及其他服务。例如,配备适当的设备可以使用蓝牙进行短距离定位。

回答by krisDrOid

Use the below code, it will give the best provider available:

使用以下代码,它将提供可用的最佳提供程序:

String locCtx = Context.LOCATION_SERVICE; 

LocationManager locationMgr = (LocationManager) ctx.getSystemService(locCtx);

Criteria criteria  = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_LOW);

String provider = locationMgr.getBestProvider(criteria, true);

System.out.println("Best Available provider::::"+provider);

回答by Matt W

The recommended way to do this is to use LocationClient:

推荐的方法是使用LocationClient

First, define location update interval values. Adjust this to your needs.

首先,定义位置更新间隔值。根据您的需要进行调整。

private static final int MILLISECONDS_PER_SECOND = 1000;
private static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
private static final int FASTEST_INTERVAL_IN_SECONDS = 1;
private static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;

Have your Activityimplement GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, and LocationListener.

让你的Activity落实GooglePlayServicesClient.ConnectionCallbacksGooglePlayServicesClient.OnConnectionFailedListener以及LocationListener

public class LocationActivity extends Activity implements 
GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {}

Then, set up a LocationClientin the onCreate()method of your Activity:

然后,LocationClientonCreate()你的方法中设置一个Activity

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mLocationClient = new LocationClient(this, this, this);

    mLocationRequest = LocationRequest.create();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequest.setInterval(UPDATE_INTERVAL);
    mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
}

Add the required methods to your Activity; onConnected()is the method that is called when the LocationClientconnects. onLocationChanged()is where you'll retrieve the most up-to-date location.

将所需的方法添加到您的Activity; onConnected()LocationClient连接时调用的方法。onLocationChanged()是您将检索最新位置的地方。

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    Log.w(TAG, "Location client connection failed");
}

@Override
public void onConnected(Bundle dataBundle) {
    Log.d(TAG, "Location client connected");
    mLocationClient.requestLocationUpdates(mLocationRequest, this); 
}

@Override
public void onDisconnected() {
    Log.d(TAG, "Location client disconnected");
}

@Override
public void onLocationChanged(Location location) {
    if (location != null) {
        Log.d(TAG, "Updated Location: " + Double.toString(location.getLatitude()) + "," + Double.toString(location.getLongitude()));
    } else {
        Log.d(TAG, "Updated location NULL");
    } 
}     

Be sure to connect/disconnect the LocationClientso it's only using extra battery when absolutely necessary and so the GPS doesn't run indefinitely. The LocationClientmust be connected in order to get data from it.

确保连接/断开连接,LocationClient以便它仅在绝对必要时使用额外的电池,因此 GPS 不会无限期运行。在LocationClient必须连接,以便从中获取数据。

public void onResume() {
    super.onResume();
    mLocationClient.connect();
}

public void onStop() {
    if (mLocationClient.isConnected()) {
        mLocationClient.removeLocationUpdates(this);
    }
    mLocationClient.disconnect();
    super.onStop();
}

Get the user's location. First try using the LocationClient; if that fails, fall back to the LocationManager.

获取用户的位置。首先尝试使用LocationClient; 如果失败,请回退到LocationManager.

public Location getLocation() {
    if (mLocationClient != null && mLocationClient.isConnected()) {
        return mLocationClient.getLastLocation();
    } else {
        LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        if (locationManager != null) {
            Location lastKnownLocationGPS = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            if (lastKnownLocationGPS != null) {
                return lastKnownLocationGPS;
            } else {
                return locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            }
        } else {
            return null;
        }
    }
}