Android location is inaccurate

荒凉一梦 提交于 2021-02-08 03:32:05

问题


I am trying to get the current user's location. I have tried to refactor my code to get better results but I just keep getting ridiculous locations in regard to the accuracy, it is between 900-600 meters.

How can I get a better result, so as to force it to an accuracy within 50m?

Here is my code:

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

Note: I am putting emphasis on static location, e.g. not moving because it may help with the answers.


回答1:


There are two factors you need to consider to obtain an accurate location:

  1. The code, eg

    • Using the correct location provider (GPS vs. network)
    • Having the right permissions in your app
  2. The device

    • Having the appropriate sensors (not all Android devices have GPS, Wifi or indeed telephony)
    • Having the appropriate sensors enabled (eg the user has not switched off GPS)
    • Having the right Google services installed (a manufacturer decision)

These are discussed below.

Code

Make sure you have followed the guidance from Android Developer (Thanks Bill Gary)

But remember that the code will work only if the device itself has the requisite HW and configuration - see below.

Device

To understand what is going wrong with your location fix, it really helps to understand how your device locates itself. Location is obtained by several technologies:

  1. GPS chipset

    • Most accurate
    • Slow
    • Need to be outside or near window
    • Requires the GPS chipset to be on
  2. MACs visible on WiFi (by querying a central DB such as Google's)

    • Often surprisingly accurate (10-100m depending on how many WiFis are present and if they are have been seen before)
    • Quite fast
    • Requires the wifi to be on
    • Requires a data connection to the Internet to be on (not necessarily on WiFi)
    • Requires Google services to be installed on the device (some cheap devices may not have this)
  3. The location of the cell-phone mast you are using (Network Provider)

    • Accurate to hundreds of meters to kilometers
    • Often immediate
    • Requires telephony to be on

When you ask for a location fix (excluding the last, cached one), a good GPS location provider actually looks at a lot more than just GPS:

  1. It starts GPS tracking if the GPS chipset is enabled

    • 10's of seconds later, and only after a fix is obtained, the LocationProvider will return the GPS location
    • Later the device will send the GPS location of the device to Google along with the visible WiFi MACs/names and Google will consolidate this to their database of WiFi APs
  2. It starts a scan of the Wifi environment, if WiFi is enabled

    • A few seconds later, when the WiFi scan is complete, it sends the results to Google's servers
    • A second or so later the servers return a location fix

Often you can see these effects on Google Maps, for example: when you start it you see a large approximate location (cell tower) from the Network Provider, a few seconds later it zooms in on an area with a greater degree of accuracy (WiFi), and finally you may get a GPS fix.

It's always worth:

  • Using the correct/generic approach to picking a LocationProvider (rather than hardcoding)
  • Checking the relevant HW sensors are present and enabled
  • Checking that Google Maps is locating your device as you expect (and if your device does not come with Google Maps, then you don't have Google Services and likely you have a very basic GPS-only provider).
  • If you suspect the GPS chipset, use a GPS app to get a detailed view of what it is doing and capable of, eg https://play.google.com/store/apps/details?id=com.eclipsim.gpsstatus2&hl=en

EDIT

From the basic results you're getting, you seem to have only results from the Network Provider. So, do:

  • Check whether GPS is on,
  • Whether your GPS receiver can get a fix (eg using a GPS app for debugging) and
  • Put some debug into your code (probably via logcat) so you can see why the isBetterLocation() method decides on one location rather than the other.



回答2:


You should set locationListeners to all available location providers as soon as possible and wait. Setting listeners ask providers to give you all data they have immediately (minTime=0, minDistance=0). Use getLastKnownLocation as first location approximation. During time you will start getting some location data from different providers. You should manually choose the most suitable for your case (most precise, I suppose). Keep waiting as long as you can (The more you wait the better location values you will probably get). When waiting time is over take the best location you've been given and start using it. You can continue listen for location updates and improve location estimation if System will be able to give you a better value.



来源:https://stackoverflow.com/questions/14183849/android-location-is-inaccurate

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!