web-dev-qa-db-fra.com

Comment puis-je vérifier l'état actuel du récepteur GPS?

Comment puis-je vérifier l'état actuel du récepteur GPS? J'ai déjà vérifié la méthode LocationListeneronStatusChanged mais, d'une manière ou d'une autre, il semble que cela ne fonctionne pas, ou tout simplement une fausse possibilité.

En gros, il me suffit de savoir si l’icône GPS en haut de l’écran clignote (pas de solution réelle) ou est fixe (la solution est disponible).

88
nr1

En tant que développeur de SpeedView: indicateur de vitesse GPS pour Android, je dois avoir essayé toutes les solutions possibles à ce problème, toutes avec le même résultat négatif. Réitérons ce qui ne fonctionne pas:

  1. onStatusChanged () n'est pas appelé sur Eclair et Froyo.
  2. Compter simplement tous les satellites disponibles est bien entendu inutile.
  3. Vérifier si l'un des satellites retourne vrai pour usedInFix () n'est pas très utile également. Le système perd clairement le correctif mais continue de signaler qu'il reste plusieurs sats utilisés.

Voici donc la seule solution de travail que j'ai trouvée et celle que j'utilise réellement dans mon application. Disons que nous avons cette classe simple qui implémente le 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, maintenant dans onLocationChanged (), nous ajoutons ce qui suit:

@Override
public void onLocationChanged(Location location) {
    if (location == null) return;

    mLastLocationMillis = SystemClock.elapsedRealtime();

    // Do something.

    mLastLocation = location;
}

Et c'est tout. En gros, c'est la ligne qui fait tout:

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

Vous pouvez modifier la valeur en millis bien sûr, mais je vous conseillerais de la régler entre 3 et 5 secondes.

Cela fonctionne réellement et bien que je n’aie pas regardé le code source qui dessine l’icône GPS native, cela revient à reproduire son comportement. J'espère que ça aide quelqu'un.

146
soundmaven

L'icône GPS semble changer d'état en fonction des intentions de diffusion reçues. Vous pouvez changer son état vous-même avec les exemples de code suivants:

Notifier que le GPS a été activé:

Intent intent = new Intent("Android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", true);
sendBroadcast(intent);

Avertissez que le GPS reçoit des correctifs:

Intent intent = new Intent("Android.location.GPS_FIX_CHANGE");
intent.putExtra("enabled", true);
sendBroadcast(intent);

Avertissez que le GPS ne reçoit plus de correctifs:

Intent intent = new Intent("Android.location.GPS_FIX_CHANGE");
intent.putExtra("enabled", false);
sendBroadcast(intent);

Notifier que le GPS a été désactivé:

Intent intent = new Intent("Android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", false);
sendBroadcast(intent);

Exemple de code pour enregistrer le destinataire aux fins suivantes:

// MyReceiver must extend BroadcastReceiver
MyReceiver receiver = new MyReceiver();
IntentFilter filter = new IntentFilter("Android.location.GPS_ENABLED_CHANGE");
filter.addAction("Android.location.GPS_FIX_CHANGE");
registerReceiver(receiver, filter);

En recevant ces intentions de diffusion, vous pouvez remarquer les changements de statut du GPS. Cependant, vous ne serez notifié que lorsque l'état changera. Il n'est donc pas possible de déterminer l'état actuel à l'aide de ces intentions.

26
sast

nouveau membre, malheureusement, je suis incapable de commenter ou de voter, mais le message ci-dessus de Stephen Daye était la solution parfaite au même problème avec lequel je cherchais de l'aide.

une petite modification à la ligne suivante:

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

à:

isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);

fondamentalement, je construis un jeu au rythme lent et mon intervalle de mise à jour est déjà réglé sur 5 secondes, une fois que le signal GPS est coupé pendant plus de 10 secondes, c'est le bon moment pour déclencher quelque chose.

cheers mate, j'ai passé environ 10 heures à essayer de résoudre cette solution avant que je trouve votre message :)

18
chich

Ok, alors essayons une combinaison de toutes les réponses et mises à jour jusqu'à présent et faisons quelque chose comme ça:

L’auditeur GPS pourrait être quelque chose comme ceci:

GpsStatus.Listener listener = new GpsStatus.Listener() {
    void onGpsStatusChanged(int event) {
        if (event == GPS_EVENT_SATELLITE_STATUS) {
            GpsStatus status = mLocManager.getGpsStatus(null);
            Iterable<GpsSatellite> sats = status.getSatellites();
            // Check number of satellites in list to determine fix state
        }
    }
}

Les API ne précisent pas quand et quelles informations GPS et satellitaires sont fournies, mais je pense qu'une idée serait de regarder combien de satellites sont disponibles. S'il est inférieur à trois, vous ne pouvez pas avoir de solution. Si c'est plus, alors vous devriez avoir une solution.

Essai et erreur est probablement le meilleur moyen de déterminer la fréquence à laquelle Android rapporte les informations du satellite et quelles informations chaque objet GpsSatellite contient.

14
Christopher Orr

Après quelques années d'utilisation de GPS sur Windows Mobile, j'ai compris que le concept de "perte" d'un repère GPS peut être subjectif. Pour écouter simplement ce que le GPS vous dit, ajouter un NMEAListener et analyser la phrase vous dira si le correctif était "valide" ou non. Voir http://www.gpsinformation.org/dale/nmea.htm#GGA . Malheureusement, avec certains GPS, cette valeur fluctue même pendant le cours normal des opérations dans une zone "en bon état".

L’autre solution consiste donc à comparer l’heure UTC de la position GPS à l’heure du téléphone (convertie en heure UTC). S'ils sont séparés d'un certain décalage horaire, vous pouvez supposer que vous avez perdu la position GPS.

8
Justin Breitfeller

si vous rencontrez un problème similaire alors que vous travaillez sur mon projet de maîtrise, il semble que la réponse de Daye indique à tort qu’il n’ya "pas de solution" alors que l’appareil reste dans un emplacement statique. J'ai légèrement modifié la solution, ce qui semble bien fonctionner pour moi dans un endroit statique. Je ne sais pas comment cela affecterait la batterie car ce n'est pas ma préoccupation principale, mais voici comment je l'ai fait en demandant à nouveau des mises à jour d'emplacement lorsqu'un délai a expiré.

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;
        }
    }
}
7
Jeffery Lee

Eh bien, la mise en place de toutes les méthodes de travail aboutira à cela (traiter également les obsolètes 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) {

}

Remarque: cette réponse est une combinaison des réponses ci-dessus.

4
Gregory Stein

Si vous avez juste besoin de savoir s’il existe une solution, recherchez le dernier emplacement connu fourni par le récepteur GPS et vérifiez la valeur .getTime () pour connaître son âge. Si c'est assez récent (comme ... quelques secondes), vous avez un correctif.

   LocationManager lm = (LocationManager)context.getSystemService(LOCATION_SERVICE); 
   Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);

   // Get the time of the last fix
   long lastFixTimeMillis = loc.getTime(); 

... et enfin, comparez cela à la date actuelle (en UTC!) Si c'est assez récent, vous avez un correctif.

Je le fais dans mon application et jusqu'ici tout va bien.

3
Adan

Vous pouvez essayer d'utiliser LocationManager.addGpsStatusListener pour être mis à jour lorsque l'état du GPS change. Cela ressemble à GPS_EVENT_STARTED et GPS_EVENT_STOPPED pourrait être ce que vous cherchez.

2
Erich Douglass

Je peux me tromper, mais il semble que les gens semblent se détourner du sujet pour

j'ai juste besoin de savoir si l'icône gps en haut de l'écran clignote (pas de solution réelle)

Cela se fait facilement avec

LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean gps_on = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);

Pour voir si vous avez une solution solide, les choses deviennent un peu plus compliquées:

public class whatever extends Activity {
    LocationManager lm;
    Location loc;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);        
        lm = (LocationManager) getSystemService(LOCATION_SERVICE);
        loc = null;
        request_updates();        
    }

    private void request_updates() {
        if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            // GPS is enabled on device so lets add a loopback for this locationmanager
            lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0, 0, locationListener);
        }      
    }

    LocationListener locationListener = new LocationListener() {
        public void onLocationChanged(Location location) {
            // Each time the location is changed we assign loc
            loc = location;
        }

         // Need these even if they do nothing. Can't remember why.
         public void onProviderDisabled(String arg0) {}
         public void onProviderEnabled(String provider) {}
         public void onStatusChanged(String provider, int status, Bundle extras) {}
    };

Maintenant, chaque fois que vous voulez voir si vous avez la solution?

if (loc != null){
    // Our location has changed at least once
    blah.....
}

Si vous voulez être chic, vous pouvez toujours avoir un délai d'attente en utilisant System.currentTimeMillis () et loc.getTime ()

Fonctionne de manière fiable, au moins sur un N1 depuis 2.1.

2
regomodo

Avec LocationManager, vous pouvez obtenirLastKnownLocation () après avoir obtenu BestProvider (). Cela vous donne un objet Location, qui a les méthodes getAccuracy () en mètres et getTime () en millisecondes UTC

Est-ce que cela vous donne assez d'informations?

Ou peut-être pourriez-vous parcourir les fournisseurs d'emplacement pour savoir si chacun d'eux correspond à des critères (ACCURACY_COARSE)

1
Mark Borgerding

tellement de messages ...

GpsStatus.Listener gpsListener = new GpsStatus.Listener() {
                        public void onGpsStatusChanged(int event) {
                            if( event == GpsStatus.GPS_EVENT_FIRST_FIX){
                                showMessageDialog("GPS fixed");
                            }
                        }
                 };

l'ajout de ce code, avec addGpsListener ... showMessageDialog ... affiche simplement une fenêtre de dialogue standard avec la chaîne

fait le travail parfaitement pour moi :) merci beaucoup: =) (sry pour ce post, pas encore en mesure de voter)

1
cV2

Je sais que c'est un peu tard. Cependant, pourquoi ne pas utiliser NMEAListener si vous voulez savoir si vous avez un correctif. D'après ce que j'ai lu, NMEAListener vous donnera les phrases NMEA et à partir de là, vous choisissez la phrase correcte.

La phrase RMC contient l'état du correctif, à savoir A pour OK ou V pour avertissement. La phrase GGA contient la qualité de correction (0 invalide, 1 GPS ou 2 DGPS)

Je ne peux vous offrir aucun code Java car je ne fais que commencer avec Android, mais j'ai créé une bibliothèque GPS en C # pour les applications Windows, que je souhaite utiliser avec Xamarin: Je n'ai trouvé ce fil que parce que je cherchais des informations sur le fournisseur.

D'après ce que j'ai lu jusqu'à présent sur l'objet Location, je ne suis pas très à l'aise avec les méthodes telles que getAccuracy () et hasAccuracy (). Je suis habitué à extraire des phrases NMEA les valeurs HDOP et VDOP afin de déterminer la précision de mes correctifs. Il est assez courant d'avoir une solution, mais d'avoir une HDOP moche, ce qui signifie que votre précision horizontale n'est pas très bonne. Par exemple, assis à votre bureau en train de déboguer avec un périphérique GPS Bluetooth externe fort contre une fenêtre, vous aurez probablement une solution, mais une qualité HDOP et VDOP très médiocre. Placez votre appareil GPS dans un pot de fleurs à l'extérieur ou quelque chose de similaire ou ajoutez une antenne externe au GPS et vous obtenez immédiatement de bonnes valeurs HDOP et VDOP.

1
user2153142

Si vous n'avez pas besoin d'une mise à jour à l'instant même où le correctif est perdu, vous pouvez modifier la solution de Stephen Daye de cette manière, en disposant d'une méthode qui vérifie si le correctif est toujours présent.

Donc, vous pouvez simplement le vérifier chaque fois que vous avez besoin de données GPS et vous n'avez pas besoin de ce GpsStatus.Listener.

Les variables "globales" sont:

private Location lastKnownLocation;
private long lastKnownLocationTimeMillis = 0;
private boolean isGpsFix = false;

C'est la méthode appelée dans "onLocationChanged ()" pour mémoriser l'heure de mise à jour et l'emplacement actuel. A côté de cela, il met à jour "isGpsFix":

private void handlePositionResults(Location location) {
        if(location == null) return;

        lastKnownLocation = location;
        lastKnownLocationTimeMillis = SystemClock.elapsedRealtime();

        checkGpsFix(); // optional
    }

Cette méthode est appelée chaque fois que j'ai besoin de savoir s'il existe un repère GPS:

private boolean checkGpsFix(){

    if (SystemClock.elapsedRealtime() - lastKnownLocationTimeMillis < 3000) {
        isGpsFix = true;

    } else {
        isGpsFix = false;
        lastKnownLocation = null;
    }
    return isGpsFix;
}

Dans mon implémentation, je lance d'abord checkGpsFix () et si le résultat est true, j'utilise la variable "lastKnownLocation" comme position actuelle.

1

Le réglage de l'intervalle de temps pour vérifier la correction n'est pas un bon choix. J'ai remarqué que onLocationChanged n'est pas appelé si vous ne déménagez pas .. ce qui est compréhensible car l'emplacement ne change pas :)

Une meilleure façon serait par exemple:

  • intervalle de contrôle jusqu'au dernier emplacement reçu (en gpsStatusChanged)
  • si cet intervalle est supérieur à 15 secondes, définissez la variable: long_interval = true
  • supprimer l'écouteur d'emplacement et l'ajouter à nouveau, vous obtenez généralement la position mise à jour si l'emplacement est vraiment disponible, sinon - vous avez probablement perdu l'emplacement
  • dans onLocationChanged vous venez de définir long_interval sur false.
0
Hardy

Vous dites que vous avez déjà essayé onStatusChanged (), mais cela fonctionne pour moi.

Voici la méthode que j'utilise (je laisse la classe elle-même gérer 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);
}

Et je gère onStatusChanged comme suit:

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

Notez que les méthodes onProvider {Dis, En} abled () concernent l’activation et la désactivation du suivi GPS par l’utilisateur; pas ce que vous cherchez.

0
CvR

C’est peut-être la meilleure possibilité de créer une TimerTask qui attribue régulièrement à l’emplacement reçu une certaine valeur (nulle?). Si une nouvelle valeur est reçue par le GPSListener, celui-ci mettra à jour l'emplacement avec les données actuelles.

Je pense que ce serait une solution de travail.

0
nr1