2

我正在尝试获取当前用户的位置。我试图重构我的代码以获得更好的结果,但我只是在准确性方面不断获得荒谬的位置,它在 900-600 米之间。

我怎样才能获得更好的结果,以使其达到 50m 以内的精度?

这是我的代码:

package com.agam.mapslocation;

import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;

public class MapsActivity extends Activity {

    private static final int ONE_MINUTE = 1000 * 60 * 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);

        final LocationManager locationManager = (LocationManager) this
                .getSystemService(Context.LOCATION_SERVICE);

        final EditText et = (EditText) findViewById(R.id.editText1);

        // Define a listener that responds to location updates
        LocationListener locationListener = new LocationListener() {
            public void onLocationChanged(Location l) {
                // Called when a new location is found by the network location
                // provider.
                Location gps = locationManager
                        .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                Location net = locationManager
                        .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

                Location bestLocation = null;
                bestLocation = isBetterLocation(gps, net);
                bestLocation = isBetterLocation(bestLocation, l);
                if(bestLocation!=null)
                    displayLocation(et, bestLocation);
            }

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

            }

            public void onProviderEnabled(String provider) {
                if (provider.equals(LocationManager.GPS_PROVIDER)) {
                    et.setText("GPS ON!");
                }
            }

            public void onProviderDisabled(String provider) {
            }
        };

        // Register the listener with the Location Manager to receive location
        // updates
        locationManager.requestLocationUpdates(
                LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
                0, locationListener);
    }

    public static void displayLocation(View v, Location l) {
        ((EditText) v).setText(String.format(
                "Long:%s,\nLat:%s,\nAccu:%s,\nTime ago:%s,\nProvider:%s",
                l.getLongitude(), l.getLatitude(), l.getAccuracy(),
                new java.util.Date().getTime() - l.getTime(), l.getProvider()));
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_maps, menu);
        return true;
    }

    /**
     * Determines whether one Location reading is better than the current
     * Location fix
     * 
     * @param location
     *            The new Location that you want to evaluate
     * @param currentBestLocation
     *            The current Location fix, to which you want to compare the new
     *            one
     */
    protected Location isBetterLocation(Location location,
            Location currentBestLocation) {
        if (currentBestLocation == null) {
            // A new location is always better than no location
            return location;
        }

        // Check whether the new location fix is newer or older
        long timeDelta = location.getTime() - currentBestLocation.getTime();
        boolean isSignificantlyNewer = timeDelta > ONE_MINUTE;
        boolean isSignificantlyOlder = timeDelta < -ONE_MINUTE;
        boolean isNewer = timeDelta > 0;

        // If it's been more than two minutes since the current location, use
        // the new location
        // because the user has likely moved
        if (isSignificantlyNewer) {
            return location;
            // If the new location is more than two minutes older, it must be
            // worse
        } else if (isSignificantlyOlder) {
            return currentBestLocation;
        }

        // Check whether the new location fix is more or less accurate
        int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
                .getAccuracy());
        boolean isLessAccurate = accuracyDelta > 0;
        boolean isMoreAccurate = accuracyDelta < 0;
        boolean isSignificantlyLessAccurate = accuracyDelta > 200;

        // Check if the old and new location are from the same provider
        boolean isFromSameProvider = isSameProvider(location.getProvider(),
                currentBestLocation.getProvider());

        // Determine location quality using a combination of timeliness and
        // accuracy
        if (isMoreAccurate) {
            return location;
        } else if (isNewer && !isLessAccurate) {
            return location;
        } else if (isNewer && !isSignificantlyLessAccurate
                && isFromSameProvider) {
            return location;
        }
        return currentBestLocation;
    }

    /** Checks whether two providers are the same */
    private boolean isSameProvider(String provider1, String provider2) {
        if (provider1 == null) {
            return provider2 == null;
        }
        return provider1.equals(provider2);
    }
}

注意:我强调静态位置,例如不要移动,因为它可能有助于答案。

4

2 回答 2

3

要获得准确的位置,您需要考虑两个因素:

  1. 代码,例如

    • 使用正确的位置提供商(GPS 与网络)
    • 在您的应用中拥有正确的权限
  2. 装置

    • 拥有合适的传感器(并非所有 Android 设备都有 GPS、Wifi 或电话)
    • 启用适当的传感器(例如,用户没有关闭 GPS)
    • 安装正确的 Google 服务(制造商决定)

这些将在下面讨论。

代码

确保您已遵循Android 开发人员的指导(感谢Bill Gary

但请记住,代码只有在设备本身具有必要的硬件和配置时才能工作 - 见下文。

设备

要了解您的位置修复出了什么问题,了解您的设备如何定位自己确实很有帮助。位置是通过几种技术获得的:

  1. GPS芯片组

    • 最准确
    • 慢的
    • 需要在窗外或靠近窗户
    • 需要开启 GPS 芯片组
  2. WiFi 上可见的 MAC(通过查询中央数据库,例如 Google 的)

    • 通常非常准确(10-100m,取决于存在的 WiFi 数量以及它们是否曾被见过)
    • 蛮快
    • 需要打开wifi
    • 需要连接到 Internet 的数据连接(不一定是 WiFi)
    • 需要在设备上安装谷歌服务(一些便宜的设备可能没有这个)
  3. 您正在使用的手机信号塔的位置(网络提供商)

    • 精确到数百米到公里
    • 通常是即时的
    • 需要开启电话

当您要求定位修复(不包括最后一个缓存的定位)时,一个好的 GPS 定位提供商实际上不仅仅关注 GPS:

  1. 如果启用了 GPS 芯片组,它将开始 GPS 跟踪

    • 10 秒后,只有在获得修复后,LocationProvider 才会返回 GPS 位置
    • 稍后,设备会将设备的 GPS 位置以及可见的 WiFi MAC/名称发送给 Google,Google 会将其整合到他们的 WiFi AP 数据库中
  2. 如果启用了 WiFi,它将开始扫描 Wifi 环境

    • 几秒钟后,当 WiFi 扫描完成时,它会将结果发送到 Google 的服务器
    • 大约一秒钟后,服务器返回位置修复

通常您可以在 Google 地图上看到这些效果,例如:当您启动它时,您会看到网络提供商提供的一个大的近似位置(手机信号塔),几秒钟后它会放大一个更精确的区域(WiFi ),最后您可能会获得 GPS 定位。

它总是值得的:

  • 使用正确/通用的方法来选择 LocationProvider(而不是硬编码)
  • 检查相关硬件传感器是否存在并启用
  • 检查 Google 地图是否按照您的预期定位您的设备(如果您的设备没有配备 Google 地图,那么您没有 Google 服务,并且可能您有一个非常基本的仅 GPS 提供商)。
  • 如果您怀疑 GPS 芯片组,请使用 GPS 应用程序详细了解它的功能和功能,例如https://play.google.com/store/apps/details?id=com.eclipsim.gpsstatus2&hl= zh

编辑

从您获得的基本结果来看,您似乎只有来自网络提供商的结果。所以,做:

  • 检查GPS是否开启,
  • 您的 GPS 接收器是否可以修复(例如使用 GPS 应用程序进行调试)和
  • 在您的代码中进行一些调试(可能通过 logcat),这样您就可以看到为什么isBetterLocation() 方法决定一个位置而不是另一个位置。
于 2013-01-09T00:27:41.600 回答
0

您应该尽快将 locationListeners 设置为所有可用的位置提供程序并等待。设置侦听器要求提供者立即向您提供他们拥有的所有数据(minTime=0,minDistance=0)。使用 getLastKnownLocation 作为第一个位置近似值。在此期间,您将开始从不同的提供商处获取一些位置数据。您应该手动选择最适合您的情况(我想是最精确的)。尽可能长时间地等待(等待的时间越长,您可能会获得更好的位置值)。等待时间结束后,请选择您获得的最佳位置并开始使用它。如果 System 能够为您提供更好的价值,您可以继续收听位置更新并改进位置估计。

于 2013-01-08T20:37:35.273 回答