web-dev-qa-db-fra.com

Le fournisseur de localisation fusionné ne semble pas utiliser le récepteur GPS

Android 4.3 sur Moto G, Android 4.4.2 sur Nexus 7 2012, Android 4.4.2 sur Nexus 5. Android = Studio 0.4.

Je ne souhaite pas recevoir de mises à jour régulières sur l'emplacement, mais simplement un emplacement précis lorsque l'utilisateur appuie sur un bouton.

J'ai suivi cet exemple: https://developer.Android.com/training/location/retrieve-current.html

Dans le fichier manifeste:

<uses-permission Android:name="Android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />

Je vérifie que les services de lecture sont disponibles à l'aide de GooglePlayServicesUtil.isGooglePlayServicesAvailable

En activité principale:

//in activity onCreate method
mLocationClient = new LocationClient(this, this, this);

@Override
protected void onStart() {
    mLocationClient.connect();
    super.onStart();
}

@Override
protected void onStop() {
    mLocationClient.disconnect();
    super.onStop();
}

//in button onclick method    
mCurrentLocation = mLocationClient.getLastLocation();

Je n'ai pas de carte SIM. Si j'active le Wifi, je reçois parfois un emplacement précis. D'autres fois, mCurrentLocation est null.

Si je désactive le Wifi, alors mCurrentLocation est toujours nul.

Je teste dehors à plusieurs endroits avec toujours une vue dégagée du ciel. J'ai attendu trois minutes à chaque endroit.

Je ne vois jamais l'icône GPS apparaître sur la barre de notification Android) en haut de l'écran.

J'ai ces paramètres de localisation: enter image description here

Une application de test GPS parvient à utiliser le GPS à l'intérieur avec succès sur le même appareil avec le Wi-Fi désactivé pour que le GPS fonctionne: enter image description here

L'enregistrement pour les mises à jour d'emplacement, à la https://developer.Android.com/training/location/receive-location-updates.html , ne fonctionne pas non plus. Méthode enregistrée jamais appelée.

Qu'est-ce que je fais mal?

38
cja

Je l'ai résolu. Le problème était que "Laisser les applications Google accéder à votre position" a été désactivé: enter image description here

Lorsque je l'allume, je reçois des relevés GPS et lorsqu'il est éteint, je ne le fais pas.

Je l'avais laissé pour deux raisons:

  1. Je développe une application pour pouvoir utiliser de nombreux appareils dans une entreprise et je souhaite une configuration manuelle minimale.

  2. L'écran indique clairement "Ce paramètre concerne uniquement les applications Google." Je sais que Play Services est un logiciel de Google, mais je ne pensais pas que Google s’attendrait à ce que l’utilisateur final le comprenne.

Ensuite, j'ai reçu la mise à jour Android 4.4.2 et la page des paramètres de localisation a été modifiée. Il semble que Google Location Reporting puisse être désactivé et que les relevés GPS du fournisseur de localisation fusionné soient toujours disponibles: enter image description here

Alors peut-être que Google s'est rendu compte que le réglage était confus et l'a amélioré. De toute façon, j'aurais gagné beaucoup de temps si j'avais eu 4.4.2 il y a quelques jours.

16
cja

Le problème est avec getLastLocation() parce qu'il utilise un emplacement mis en cache. J'ai eu le même problème car j'ai également essayé d'utiliser cette approche simple. Depuis, je suis passé à l'écoute des mises à jour (et à l'arrêt automatique après la première mise à jour).

Ceci est mon code qui fonctionne.

Tout d'abord, le contrôle de disponibilité dans l'application (non essentiel, peut être dans l'activité et sans conservation du résultat):

public class MainApp extends Application {
  public static enum PlayServices {
    NOT_CHECKED, AVAILABLE, UNAVAILABLE
  };
  public static PlayServices mPlayServices = PlayServices.NOT_CHECKED;

  @Override
  public void onCreate() {
    super.onCreate();

    if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
      MainApp.mPlayServices = MainApp.PlayServices.AVAILABLE;
    }
  }
}

Ensuite, pour l'activité:

public class MainActivity extends SherlockFragmentActivity implements
  GooglePlayServicesClient.ConnectionCallbacks,
  GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {

Dans sa onCreate():

if (MainApp.mPlayServices != MainApp.PlayServices.UNAVAILABLE) {
  mLocationClient = new LocationClient(this, this, this);

  mLocationRequest = LocationRequest.create();
  mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
  mLocationRequest.setInterval(5000);
  mLocationRequest.setNumUpdates(1);
  mLocationRequest.setFastestInterval(1000);

  mUpdatesRequested = false;
  MainApp.prefs.edit().putBoolean(MainApp.KEY_LOCATION_UPDATES_REQUESTED, mUpdatesRequested)
      .commit();
}

Le reste de la classe MainActivity:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  Log.d(this.getClass().getSimpleName(), "onActivityResult(" + requestCode + ", " + resultCode
      + ")");
  // Decide what to do based on the original request code
  switch (requestCode) {
    case MainApp.PLAY_CONNECTION_FAILURE_RESOLUTION_REQUEST:
      /*
       * If the result code is Activity.RESULT_OK, try
       * to connect again
       */
      switch (resultCode) {
        case Activity.RESULT_OK:
          // here we want to initiate location requests!
          mLocationClient = new LocationClient(this, this, this);

          break;
      }
      break;
  }
}

@Override
public void onConnected(Bundle dataBundle) {
  Log.d(this.getClass().getSimpleName(), "onConnected()");

  Log.d(this.getClass().getSimpleName(), "Google Play Services are available.");
  MainApp.mPlayServices = MainApp.PlayServices.AVAILABLE;

  if (!mUpdatesRequested) {

    LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    boolean gps_enabled = false;
    try {
      gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
    } catch (Exception ex) {
    }

    boolean network_enabled = false;
    try {
      network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    } catch (Exception ex) {
    }

    // don't start listeners if no provider is enabled
    MainApp.locEnabled = gps_enabled || network_enabled;

    if (!MainApp.locEnabled) {
      // we have access to PlayServices, but user has disabled location visibility --> alert him
      alertLocationOff();
    } else {
      mLocationClient.requestLocationUpdates(mLocationRequest, this);
      mUpdatesRequested = true;
    }
  }
}

@Override
public void onDisconnected() {
  Log.d(this.getClass().getSimpleName(), "onDisconnected()");
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
  Log.d(this.getClass().getSimpleName(), "onConnectionFailed()");

  Log.d(this.getClass().getSimpleName(), "Google Play Services not available.");
  MainApp.mPlayServices = MainApp.PlayServices.UNAVAILABLE;

  /*
   * Google Play services can resolve some errors it detects.
   * If the error has a resolution, try sending an Intent to
   * start a Google Play services activity that can resolve
   * error.
   */
  if (connectionResult.hasResolution()) {
    try {
      // Start an Activity that tries to resolve the error
      connectionResult.startResolutionForResult(this,
          MainApp.PLAY_CONNECTION_FAILURE_RESOLUTION_REQUEST);
      /*
       * Thrown if Google Play services canceled the original
       * PendingIntent
       */
    } catch (IntentSender.SendIntentException e) {
      // Log the error
      e.printStackTrace();
    }
  } else {
    /*
     * If no resolution is available, display a dialog to the
     * user with the error.
     */
    GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), this, 0).show();
  }
}

@SuppressLint("NewApi")
@Override
public void onLocationChanged(Location location) {
  Log.d(this.getClass().getSimpleName(), "onLocationChanged(), location=" + location);

  if (location != null) {
    boolean present = true;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Gingerbread) {
      present = Geocoder.isPresent();
    }

    if (present) {
      (new ExtractLocationTask(this)).execute(location);
    } else {
      Log.e(this.getClass().getSimpleName(), "Geocoder not present");
      MainApp.mPlayServices = MainApp.PlayServices.UNAVAILABLE;
    }
  }
}


private class ExtractLocationTask extends AsyncTask<Location, Void, Boolean> {
  Context mContext;

  public ExtractLocationTask(Context context) {
    super();
    mContext = context;
  }

  @Override
  protected Boolean doInBackground(Location... params) {
    Log.d(getClass().getSimpleName(), "ExtractLocationTask.onPreExecute()");

    boolean found = false;
    try {
      Geocoder geoCoder_local = new Geocoder(mContext, Locale.getDefault());
      Geocoder geoCoder_en = new Geocoder(mContext, Locale.ENGLISH);

      List<Address> addresses_local = geoCoder_local.getFromLocation(params[0].getLatitude(),
          params[0].getLongitude(), 10);
      List<Address> addresses_en = geoCoder_en.getFromLocation(params[0].getLatitude(),
          params[0].getLongitude(), 10);

      if (addresses_local != null && addresses_local.size() > 0) {

        // do what you want with location info here

        // based on mLocationRequest.setNumUpdates(1), no need to call
        // removeLocationUpdates()

        MainApp.locEnabled = true;

        mUpdatesRequested = false;
        MainApp.prefs.edit()
            .putBoolean(MainApp.KEY_LOCATION_UPDATES_REQUESTED, mUpdatesRequested).commit();

        found = true;
      }
    } catch (IOException e) {
      Log.e(this.getClass().getSimpleName(), "Exception: ", e);
    }

    return found;
  }

  @Override
  protected void onPostExecute(Boolean found) {
    Log.d(getClass().getSimpleName(), "ExtractLocationTask.onPostExecute()");

    if (found) {
      // update UI etc.
    } else if (!mUpdatesReRequested) {
      mLocationClient.requestLocationUpdates(mLocationRequest, (LocationListener) mContext);
      mUpdatesRequested = true;
      mUpdatesReRequested = true;
    }
  }
}

J'espère que cela vous aidera à le faire fonctionner!

15
Saran

Le fournisseur de localisation ne réveille le GPS que lorsque certains clients demandent (s'abonner) une localisation de haute précision (comme décrit dans les exemples donnés par d'autres utilisateurs). L'application de test GPS n'utilise pas le fournisseur de localisation mais utilise l'ancien moyen "direct" d'obtenir la localisation.

Il existe également un mécanisme d'expiration, qui supprime les informations sur le dernier emplacement après un certain temps s'il est considéré comme obsolète.

En résumé, il est fort possible que LP (Location Provider) n’ait rien à vous donner.

4
Andrew

Je pense que vous testez votre application en intérieur, cela ne fonctionne pas ..

et le flux de code ..

public void setUpLocationClientIfNeeded() {
        createLocReq();
        if (mLocationClient == null) {
            mLocationClient = new LocationClient(getApplicationContext(), this, // ConnectionCallbacks
                    this); // OnConnectionFailedListener
        }
    }

    private void createLocReq() {
        if (mLocationRequest == null) {
            // Create a new global location parameters object
            mLocationRequest = LocationRequest.create();
            // Set the update interval
            mLocationRequest.setInterval(LocationServices.UPDATE_INTERVAL_IN_MILLISECONDS);
            // Use high accuracy
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            // Set the interval ceiling to one minute
            mLocationRequest.setFastestInterval(LocationServices.FAST_INTERVAL_CEILING_IN_MILLISECONDS);

            mLocationClient = new LocationClient(getApplicationContext(), this, this);
            mLocationClient.connect();
        }
    }

    public void updateLocation(Location location) {
        if (lastTrackedLat == 0.0) {
            lastTrackedLat = location.getLatitude();
        }
        if (lastTrackedLng == 0.0) {
            lastTrackedLng = location.getLongitude();
        }

        currentLat = location.getLatitude();
        currentLng = location.getLongitude();
    }

    @Override
    public void onLocationChanged(Location location) {
        if (location != null) {
            this.location = location;
            updateLocation(location);
        }
    }

    public Location getLocation() {
        // mLocationClient.getLastLocation();
        return location;
    }
2
vinay Maneti

Selon les docs

Cette méthode offre un moyen simplifié d’obtenir un emplacement. Il est particulièrement bien adapté aux applications ne nécessitant pas d'emplacement précis et ne souhaitant pas conserver de logique supplémentaire pour les mises à jour d'emplacement.

de sorte qu'il peut ou non renvoyer un emplacement très précis.

Le GPS peut prendre un certain temps à se verrouiller, alors appeler getLastLocation peut ou non renvoyer une position.

vous feriez mieux de demander des mises à jour d'emplacement, alors après avoir obtenu un emplacement, arrêtez simplement de demander des mises à jour d'emplacement.

En regardant également le code que vous avez fourni, attendez-vous que le LocationClient se connecte avant d'essayer d'obtenir un emplacement? Cela vous donnera certainement un emplacement nul puisqu'il n'est pas encore connecté pour obtenir l'emplacement.

ce que vous devriez faire est dans votre onConnected obtenir le dernier emplacement, exemple

public void onConnected(Bundle connectionHint) {
    Location location = mLocationClient.getLastLocation();
}

comme il est dit dans cet exemple onConnected est Called by Location Services when the request to connect the client finishes successfully. At this point, you can request the current location or start periodic updates

1
tyczj

Tout ce que vous avez à faire est d’ajouter une propriété prioritaire à l’objet requête comme ceci.

public void onConnected(Bundle arg0)
{
    locationrequest = LocationRequest.create();
    locationrequest.setInterval(1000);
    locationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationclient.requestLocationUpdates(locationrequest, this);
}

Peut-être utiliser une variable booléenne pour permettre à l'utilisateur de choisir entre forcer le GPS

boolean forceGPS=false;
.
.
.//make the user choose to change the value of the boolean
.
.
public void onConnected(Bundle arg0)
    {
        locationrequest = LocationRequest.create();
        locationrequest.setInterval(1000);
        if(forceGPS==true)
        {
        locationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        }
        locationclient.requestLocationUpdates(locationrequest, this);
    }
1
Sujal Mandal

Qu'y a-t-il dans la méthode OnConnected?

Dans cette méthode, vous devriez créer l'objet LocationRequest avec PRIORITY_HIGH_ACCURACY priorité.

@Override
public void onConnected(Bundle dataBundle) {
    mLocationRequest = LocationRequest.create();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationClient.requestLocationUpdates(mLocationRequest, fusedListener);
}
1
dan_flo10

Sans carte SIM, le coarse location provider n'a aucun moyen de connaître la position grossière, à moins de pouvoir trouver un réseau WiFi mappé par Google.

Demander le dernier emplacement connu peut aboutir à un emplacement obsolète et, en tant que tel, est plutôt inutile. Je suppose que c'est la position qui a été enregistrée la dernière fois qu'une application a demandé une mise à jour d'emplacement.

J'utilise le code suivant pour obtenir un emplacement récent:

    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_COARSE);
    criteria.setAltitudeRequired(false);
    criteria.setSpeedRequired(false);
    criteria.setBearingRequired(false);
    criteria.setCostAllowed(false);

    final LocationManager manager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

    ....
    LocationListener listener = new LocationListener() {
        @Override
        public void onLocationChanged(Location lastKnownLocation) {
                     ....
        }
        // rest of interface
     }


     manager.requestSingleUpdate(criteria, listener, null);

Le dernier appel garantit que nous demandons l'emplacement actuel, pas l'emplacement où il a été trouvé auparavant.

Vous pouvez essayer de le changer en Criteria.ACCURACY_FINE afin de mettre le GPS en marche. Sachez que si le GPS n’a pas eu de solution pendant un bon moment, il peut s'écouler plusieurs minutes avant qu’il soit réellement capable de l’obtenir. Je m'attendrais en même temps à voir l'icône du GPS indiquant qu'elle attend une solution.

1
M. le Rutte

Puisque personne n'a partagé ce lien, j'ai trouvé que c'était la documentation la plus utile http://developer.Android.com/guide/topics/location/strategies.html

"Vous pouvez vous attendre à ce que le correctif de localisation le plus récent soit le plus précis. Toutefois, comme l'exactitude varie, le correctif le plus récent n'est pas toujours le meilleur. Vous devez inclure une logique permettant de choisir des correctifs de localisation en fonction de plusieurs critères. Les critères varient également en fonction des cas d'utilisation de l'application et des tests sur le terrain. "

Votre meilleur choix est de garder un écouteur d'emplacement actif tant que l'activité est au premier plan et de sélectionner l'emplacement mis en cache le plus précis lorsque vous appuyez sur le bouton. Il se peut que vous deviez afficher une visionneuse ou quelque chose du même genre et désactiver le bouton pendant qu’il attend une mesure précise à afficher.

0
Eric Woodruff

Essaye ça:

public final static int MINACCURACY = 50;

private LocationManager lm;
private LocationListener listener;

private void foundLoc(double x, double y) {
    // do something with x,y
    Log.v("DEBUG", x + "," + y);
}


public void findMe(View v) {
    lm = (LocationManager) getSystemService(LOCATION_SERVICE);
    listener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            if(location.getAccuracy() < MINACCURACY) {
                foundLoc(location.getLatitude(), location.getLongitude());
                lm.removeUpdates(listener);
            }
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onProviderDisabled(String provider) {
        }
    };
    lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 100, 0, listener);
}

MINACCURACY est en mètres. De cette façon, lorsque vous appuyez sur un bouton (qui appelle la méthode findMe), le GPS est activé, votre position est trouvée avec une précision minimale, la méthode foundLoc récupère les données et l'auditeur se termine (ce qui désactive le GPS).

0
c0m3tx

Il y a deux choses qui se passent ici et qui vous font parfois obtenir null et parfois un emplacement.

Tout d'abord, vous créez une nouvelle instance de LocationClient dans la méthode onClick, qui n'est pas la même instance que vous appelez connect() dans onStart(). Cela créera un comportement imprévisible où le client aura parfois suffisamment de temps pour se connecter avant de renvoyer un résultat de LocationClient.getLastLocation(), et parfois non.

Deuxièmement, vous devriez garder l'appel à LocationClient.getLastLocation() avec un appel à LocationClient.isConnected(). Dans la documentation LocationClient.isConnected(), il indique ce qui suit: https://developer.Android.com/reference/com/google/Android/gms/location/LocationClient.html#isConnected ()

Vérifie si le client est actuellement connecté au service afin que les requêtes adressées à d'autres méthodes aboutissent. Les applications doivent protéger les actions du client causées par l'utilisateur avec un appel à cette méthode.

Puisque l'utilisateur déclenche le code onClick() en appuyant sur le bouton, vous devez appeler cette méthode avant d'essayer d'obtenir le dernier emplacement.

Donc, votre code devrait ressembler à ceci:

LocationClient mLocationClient;
Location mCurrentLocation;

@Override
protected void onCreate() {
    ...
    mLocationClient = new LocationClient(this, this, this);
    ...
}

@Override
protected void onStart() {
    mLocationClient.connect();
    super.onStart();
}

@Override
protected void onStop() {
    mLocationClient.disconnect();
    super.onStop();
}

public void onClick(View v) {
    ...
    if (mLocationClient.isConnected()) {
        // You should get a valid location here
        mCurrentLocation = mLocationClient.getLastLocation();
    }
}

Cela devrait donner au LocationClient un temps suffisant pour se connecter et vous donner un emplacement valide, qui devrait inclure les données GPS.

0
Sean Barbeau

Je préfère utiliser le service qui implémente LocationListener pour obtenir un emplacement actuel presque précis. Je prends normalement les mesures suivantes:

  1. Initialiser LocationManager et appeler requestLocationUpdates pour GPS_PROVIDER Et NETWORK_PROVIDER Dans onCreate()
  2. Appelez getLastKnownLocation pour GPS_PROVIDER Et NETWORK_PROVIDER Et utilisez getTime() pour connaître le dernier emplacement le plus récent.
  3. Diffuser le dernier emplacement (s'il a moins de 30 secondes) (facultatif)
  4. En attendant, lorsque onLocationChanged est appelé, je compare le dernier emplacement mis à jour au dernier meilleur emplacement (le cas échéant) et vérifie le niveau de précision.
  5. Si précision delta <MIN_ACCURACY (variable utilisateur), utilisez-la comme meilleur emplacement
  6. Diffuser le meilleur emplacement actuel
  7. Doit supprimer LocationManager locationManager.removeUpdates(this);
  8. Appelez stopSelf (); (vous pouvez également arrêter le service depuis l'activité onDestroy)

MODIFIER:

OK ... La méthode ci-dessus utilisait Location API, j'ai codé ci-dessous à l'aide de Fused Provider (GooglePlayServices). J'ai testé sur mon Nexus 5 (Android 4.4.2), NO SIM, NO WIFI ... et j'obtiens des résultats.

Edit 2: J'ai aussi testé sur Android 2.3.3 LG Optimus (Pas de SIM ni de Wifi)) et il a fallu environ 5 minutes pour obtenir le verrouillage (avec Fused Fourni), mais je devenais instantanément icône de localisation.

public class HomeActivity extends FragmentActivity implements
        ActionBar.OnNavigationListener,
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {

    private LocationClient locationClient;
    private LocationRequest locationRequest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_home);
            // ...
            int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (resp == ConnectionResult.SUCCESS) {
            locationClient = new LocationClient(this, this, this);
            locationClient.connect();
        } else {
            Toast.makeText(this, "Google Play Service Error " + resp,
                    Toast.LENGTH_LONG).show();

        }
    }

    @Override
    public void onConnected(Bundle connectionHint) {
        if (locationClient != null && locationClient.isConnected()) {

            locationRequest = LocationRequest.create();
            locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            locationRequest.setInterval(100);
            locationClient.requestLocationUpdates(locationRequest, this);

        }
    }

    @Override
    public void onLocationChanged(Location location) {

        try {
            if (location != null) {
                LatLng gps = new LatLng(location.getLatitude(), location.getLongitude());
                Log.v("JD", "My Location: " + gps.toString());
            }
        } catch (Exception e) {
            Log.d("JD",
                    "onLocationChanged", e);

        }       
    }
}
0
Tamal