How can I check the current status of the GPS receiver?

前端 未结 17 1592
时光取名叫无心
时光取名叫无心 2020-11-22 08:53

How can I check the current status of the GPS receiver? I already checked the LocationListener onStatusChanged method but somehow it seems that is not working,

相关标签:
17条回答
  • 2020-11-22 09:28

    You say that you already tried onStatusChanged(), but that does work for me.

    Here's the method I use (I let the class itself handle the onStatusChanged):

    private void startLocationTracking() {
        final int updateTime = 2000; // ms
        final int updateDistance = 10; // meter
        final Criteria criteria = new Criteria();
        criteria.setCostAllowed(false);
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        final String p = locationManager.getBestProvider(criteria, true);
        locationManager.requestLocationUpdates(p, updateTime, updateDistance,
                this);
    }
    

    And I handle the onStatusChanged as follows:

    void onStatusChanged(final String provider, final int status,
            final Bundle extras) {
        switch (status) {
        case LocationProvider.OUT_OF_SERVICE:
            if (location == null || location.getProvider().equals(provider)) {
                statusString = "No Service";
                location = null;
            }
            break;
        case LocationProvider.TEMPORARILY_UNAVAILABLE:
            if (location == null || location.getProvider().equals(provider)) {
                statusString = "no fix";
            }
            break;
        case LocationProvider.AVAILABLE:
            statusString = "fix";
            break;
        }
    }
    

    Note that the onProvider{Dis,En}abled() methods are about enabling and disabling GPS tracking by the user; not what you're looking for.

    0 讨论(0)
  • 2020-11-22 09:30

    get into similar problem while working on my MSc project, it seems that Daye's answer mistakenly reported "no fix" while the device stays in a static location. I've modified the solution just a little bit which seems to work fine for me in a static location. I don't how would it affect the battery as it is not my main concern, but here's how i did it by re-requesting location updates when a fix has timed out.

    private class MyGPSListener implements GpsStatus.Listener {
        public void onGpsStatusChanged(int event) {
            switch (event) {
            case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                if (Global.getInstance().currentGPSLocation != null)
                {
                    if((SystemClock.elapsedRealtime() - mLastLocationMillis) < 20000)
                    {
                        if (!hasGPSFix) 
                            Log.i("GPS","Fix Acquired");
                        hasGPSFix = true;
                    } 
                    else
                    {
                        if (hasGPSFix) 
                        {
                            Log.i("GPS","Fix Lost (expired)");
                            lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 10, locationListener);
                        }
                        hasGPSFix = false;
                    }
                }
                break;
            case GpsStatus.GPS_EVENT_FIRST_FIX:
                Log.i("GPS", "First Fix/ Refix");
                hasGPSFix = true;
                break;
            case GpsStatus.GPS_EVENT_STARTED:
                Log.i("GPS", "Started!");
                break;
            case GpsStatus.GPS_EVENT_STOPPED:
                Log.i("GPS", "Stopped");
                break;
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 09:31

    Setting time interval to check for fix is not a good choice.. i noticed that onLocationChanged is not called if you are not moving.. what is understandable since location is not changing :)

    Better way would be for example:

    • check interval to last location received (in gpsStatusChanged)
    • if that interval is more than 15s set variable: long_interval = true
    • remove the location listener and add it again, usually then you get updated position if location really is available, if not - you probably lost location
    • in onLocationChanged you just set long_interval to false..
    0 讨论(0)
  • 2020-11-22 09:34

    After a few years of working with GPS on windows mobile, I realized that the concept of "losing" a GPS fix can be subjective. To simply listen to what the GPS tells you, adding a NMEAListener and parsing the sentence will tell you whether the fix was "valid" or not. See http://www.gpsinformation.org/dale/nmea.htm#GGA . Unfortunately with some GPSes this value will fluctuate back and forth even during the normal course of operation in a "good fix" area.

    So, the other solution is to compare the UTC time of the GPS location against the phone's time (converted to UTC). If they are a certain time difference apart, you can assume you lost the GPS position.

    0 讨论(0)
  • 2020-11-22 09:34

    Well, putting together every working approach will result in this (also dealing with deprecated GpsStatus.Listener):

    private GnssStatus.Callback mGnssStatusCallback;
    @Deprecated private GpsStatus.Listener mStatusListener;
    private LocationManager mLocationManager;
    
    @Override
    public void onCreate() {
        mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    
        mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        if (checkPermission()) {
           mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_UPDATE_INTERVAL, MIN_DISTANCE, this);
        }
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            mGnssStatusCallback = new GnssStatus.Callback() {
                @Override
                public void onSatelliteStatusChanged(GnssStatus status) {
                    satelliteStatusChanged();
                }
    
                @Override
                public void onFirstFix(int ttffMillis) {
                    gpsFixAcquired();
    
                }
            };
            mLocationManager.registerGnssStatusCallback(mGnssStatusCallback);
        } else {
            mStatusListener = new GpsStatus.Listener() {
                @Override
                public void onGpsStatusChanged(int event) {
                    switch (event) {
                        case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                            satelliteStatusChanged();
                            break;
                        case GpsStatus.GPS_EVENT_FIRST_FIX:
                            // Do something.
                            gpsFixAcquired();
                            break;
                    }
                }
            };
            mLocationManager.addGpsStatusListener(mStatusListener);
        }
    }
    
    private void gpsFixAcquired() {
        // Do something.
        isGPSFix = true;
    }
    
    private void satelliteStatusChanged() {
        if (mLastLocation != null)
            isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);
    
        if (isGPSFix) { // A fix has been acquired.
            // Do something.
        } else { // The fix has been lost.
            // Do something.
        }
    }
    
    @Override
    public void onLocationChanged(Location location) {
        if (location == null) return;
    
        mLastLocationMillis = SystemClock.elapsedRealtime();
    
        mLastLocation = location;
    }
    
    @Override
    public void onStatusChanged(String s, int i, Bundle bundle) {
    
    }
    
    @Override
    public void onProviderEnabled(String s) {
    
    }
    
    @Override
    public void onProviderDisabled(String s) {
    
    }
    

    Note: this answer is a combination of the answers above.

    0 讨论(0)
  • 2020-11-22 09:35

    As a developer of SpeedView: GPS speedometer for Android, I must have tried every possible solution to this problem, all with the same negative result. Let's reiterate what doesn't work:

    1. onStatusChanged() isn't getting called on Eclair and Froyo.
    2. Simply counting all available satellites is, of course, useless.
    3. Checking if any of the satellites return true for usedInFix() isn't very helpful also. The system clearly loses the fix but keeps reporting that there are still several sats that are used in it.

    So here's the only working solution I found, and the one that I actually use in my app. Let's say we have this simple class that implements the GpsStatus.Listener:

    private class MyGPSListener implements GpsStatus.Listener {
        public void onGpsStatusChanged(int event) {
            switch (event) {
                case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                    if (mLastLocation != null)
                        isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
    
                    if (isGPSFix) { // A fix has been acquired.
                        // Do something.
                    } else { // The fix has been lost.
                        // Do something.
                    }
    
                    break;
                case GpsStatus.GPS_EVENT_FIRST_FIX:
                    // Do something.
                    isGPSFix = true;
    
                    break;
            }
        }
    }
    

    OK, now in onLocationChanged() we add the following:

    @Override
    public void onLocationChanged(Location location) {
        if (location == null) return;
    
        mLastLocationMillis = SystemClock.elapsedRealtime();
    
        // Do something.
    
        mLastLocation = location;
    }
    

    And that's it. Basically, this is the line that does it all:

    isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
    

    You can tweak the millis value of course, but I'd suggest to set it around 3-5 seconds.

    This actually works and although I haven't looked at the source code that draws the native GPS icon, this comes close to replicating its behaviour. Hope this helps someone.

    0 讨论(0)
提交回复
热议问题