Android位置不准确

时间:2013-01-06 15:56:46

标签: android location

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

如何才能获得更好的结果,以便将其强制到50米以内?

这是我的代码:

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

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

2 个答案:

答案 0 :(得分:3)

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

  1. 代码,例如

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

    • 拥有合适的传感器(并非所有Android设备都具有GPS,Wifi或电话)
    • 启用适当的传感器(例如,用户未关闭GPS)
    • 安装了正确的Google服务(制造商决定)
  3. 这些将在下面讨论。

    <强>代码

    确保您已遵循Android Developer(感谢Bill Gary

    的指导

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

    设备

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

    1. GPS芯片组

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

      • 通常令人惊讶的准确(10-100米取决于存在多少WiF,以及之前是否曾见过)
      • 很快
      • 要求wifi开启
      • 需要与Internet建立数据连接(不一定是在WiFi上)
      • 要求在设备上安装Google服务(某些便宜的设备可能没有此功能)
    3. 您正在使用的手机桅杆的位置(网络提供商)

      • 精确到几百米到几公里
      • 经常立即
      • 要求电话开启
    4. 当你要求定位(不包括最后一个,缓存的定位)时,一个优秀的GPS定位提供商实际上看起来不仅仅是GPS:

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

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

        • 几秒钟后,当WiFi扫描完成后,它会将结果发送到Google的服务器
        • 服务器返回位置修复
        • 后大约一秒钟
      3. 通常,您可以在Google地图上看到这些效果,例如:当您启动它时,您会看到来自网络提供商的大型大致位置(手机信号塔),几秒钟后它会放大更大程度的精度(WiFi),最后你可以获得GPS修复。

        总值得:

        修改

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

        • 检查GPS是否已开启,
        • 您的GPS接收器是否可以修复(例如使用GPS应用程序进行调试)和
        • 将一些调试放入您的代码中(可能通过logcat),这样您就可以看到为什么 isBetterLocation()方法决定一个位置而不是另一个位置。

答案 1 :(得分:0)

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