Android位置不准确

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android位置不准确相关的知识,希望对你有一定的参考价值。

我想获取当前用户的位置。我试图重构我的代码以获得更好的结果,但我只是在准确性方面保持荒谬的位置,它在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,
Lat:%s,
Accu:%s,
Time ago:%s,
Provider:%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);
    }
}

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

答案

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

  1. 代码,例如 使用正确的位置提供商(GPS与网络) 在您的应用中拥有正确的权限
  2. 装置 拥有合适的传感器(并非所有Android设备都有GPS,Wifi或电话) 启用适当的传感器(例如,用户未关闭GPS) 安装了正确的Google服务(制造商决定)

这些将在下面讨论。

确保你遵循了Android Developer的指导(谢谢Bill Gary

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

设备

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

  1. GPS芯片组 最准确的 慢 需要在窗户外面或附近 需要GPS芯片组打开
  2. WiFi上可见MAC(通过查询Google等中央数据库) 通常令人惊讶的准确(10-100米取决于存在多少WiF,以及之前是否曾见过) 蛮快 需要wifi才能打开 需要连接到Internet的数据连接(不一定是在WiFi上) 需要在设备上安装Google服务(某些便宜的设备可能没有此功能)
  3. 您正在使用的手机桅杆的位置(网络提供商) 准确到几百米到几公里 经常立即 需要打电话

当你要求一个位置修复(不包括最后一个,缓存的),一个好的GPS位置提供商实际上看起来不仅仅是GPS:

  1. 如果启用GPS芯片组,它将启动GPS跟踪 10秒后,只有在获得修复后,LocationProvider才会返回GPS位置 稍后该设备会将设备的GPS位置以及可见的WiFi MAC /名称发送给Google,Google会将其整合到他们的WiFi AP数据库中
  2. 如果启用了WiFi,它将开始扫描Wifi环境 几秒钟后,当WiFi扫描完成后,它会将结果发送到Google的服务器 大约一秒钟后,服务器返回一个位置修复程序

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

它始终值得:

编辑

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

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

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

以上是关于Android位置不准确的主要内容,如果未能解决你的问题,请参考以下文章

Android 更改位置准确性

我的 Android 程序上的 GPS 坐标不准确

如何在不在 android 的 Activity 上添加地图片段的情况下获取我的位置?

Android GPS 需要一段时间才能准确

Android 逆向Android 进程注入工具开发 ( Visual Studio 开发 Android NDK 应用 | Visual Studio 中 SDK 和 NDK 安装位置 )(代码片段

Android Jetpack 导航禁用滚动位置