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

标签 android geolocation location latitude-longitude

Android 上的 LocationManager API 对于只需要偶尔粗略估计用户位置的应用程序似乎有点痛苦。

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

这是我想做的:

  1. 向用户显示附近位置的列表。
  2. 预加载用户的位置,这样当我在 Activity X 中需要它时,它就可用了。
  3. 我并不特别关心更新的准确性或频率。只要不远,只需捕获一个位置就足够了。也许如果我想变得漂亮,我会每隔几分钟左右更新一次位置,但这不是一个重要的优先事项。
  4. 适用于任何具有 GPS 或网络位置提供程序的设备。

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

有没有更简单的方法来做到这一点?

最佳答案

这是我的工作:

  1. 首先,我检查启用了哪些提供程序。有些可能在设备上被禁用,有些可能在应用程序 list 中被禁用。
  2. 如果有任何提供程序可用,我将启动位置监听器和超时计时器。在我的例子中是 20 秒,对于 GPS 来说可能不够,所以你可以放大它。
  3. 如果我从位置监听器获取更新,我会使用提供的值。我停止监听器和计时器。
  4. 如果我没有得到任何更新并且计时器已过,我必须使用最后一个已知值。
  5. 我从可用的提供程序中获取最后已知的值并选择其中最新的值。

这是我使用类(class)的方式:

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

这是 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);
    }
}

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

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

关于android - 在 Android 上获取用户当前位置的最简单、最可靠的方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3145089/

相关文章:

javascript - 没有任何 map 的 Javascript 地理定位

java - Android 地理位置(当应用程序未运行时)

android - 在 Android 应用程序中检测互联网连接?

android - 扩展 AbsListView 示例

android - 如何从 Android 手机屏幕捕获视频流并将其显示在笔记本电脑上?

android - 获取用户当前位置android

PHP header Location 在 HTML 中间工作

android - AdSize.BANNER 的大小(以像素为单位)是多少?

mysql - 设置点列的默认值

Android GPS 坐标散点