2017-02-13 26 views
32

Mamy aplikacja, która rejestruje lokalizację użytkownika przy użyciu Google Play Service Location API dla każdej transakcji, jak geotag ziemi, po złożeniu zamówienia itpGoogle Play Service Location API zwraca niewłaściwą lokalizację czasami

Po zrobieniu te lokalizacje z przenośnych zsynchronizuję to z serwerem i pokażę go w panelu internetowym.

Zauważyliśmy, że w kilku przypadkach transakcja przechwycona w ciągu kilku sekund ma wyniki lokalizacji o różnej odległości.


Przykład:
Położenie użytkownik będzie w

Mandsaur, Madhya Pradesh, Indie, Azja
(Latitude - 24,057291, Długość - +75,0970672, Zapisana data - 2017-01- 04 09:19:48).

Ale kolejne transakcje będą miały lokalizację

Paris który jest 6772 km stąd
(Latitude - +48,8581074, Długość - 2,3525187, Zapisana data - 2017-01-04 09:20:01)


czasami jego błędne pobieraniu stwierdził z Indiach jak użytkownik jest z Gujrat następnie lokalizacja sprowadzić Bihar, Maharastra, Kuwejt (z Indii) jest naprawdę ból głowy dla indian developer


Dzieje się to bez ingerencji użytkowników i bez fałszywych aplikacji lokalizacyjnych zainstalowanych w urządzeniu użytkownika.

Czy ktoś może wyjaśnić, dlaczego tak się dzieje i jak możemy uniknąć tych scenariuszy?


UWAGA:
Te lokalizacje transakcyjne są ujęte zwykle w otwartym polu z GPS włączone i ustawione na tryb wysokiej dokładności

+0

Czy używasz google skondensowany api? Jeśli tak, to która wersja? – Umar

+0

Tak, używamy zintegrowanego API ** com.google.android.gms: play-services-location: 10.0.1 ** –

+0

Myślę, że to samo pytanie zostało zadane [tutaj] (http://stackoverflow.com/questions/35095177/google-play-services-location-api-czasami-give-wrong-location) o niedokładności Map Google. – noogui

Odpowiedz

1

miałem ten sam problem na Pune w Indiach. Urządzenie wykorzystywane do testu było Swipe tabletka,

Rozwiązanie : i zachować ostatni szerokości, długości i aktualizacji czasu, gdy obok szerokość i zmiana długości geograficznej, obliczyć odległość między tym dwóch miejscach, jeśli odległość jest większa niż 100 KM, to się nie policzy.

Metoda użyłem obliczyć odległość

public static double calculateDistance(double lat1,double lon1,double lat2,double lon2) { 

    double theta = lon1 - lon2; 
    double dist = Math.sin(deg2rad(lat1)) 
      * Math.sin(deg2rad(lat2)) 
      + Math.cos(deg2rad(lat1)) 
      * Math.cos(deg2rad(lat2)) 
      * Math.cos(deg2rad(theta)); 
    dist = Math.acos(dist); 
    dist = rad2deg(dist); 
    dist = dist * 60 * 1.1515; 
    return (dist); 
}  

Dlaczego zdarza

na Android urządzenia są 2 opcje, aby uzyskać położenie

  • GPS
  • Internet

GPS (LocationManager.GPS_PROVIDER): jest powolny w porównaniu do internetu, ale to będzie dokładne niż internet, w odległych obszarach GPS połączenie będzie wolniej i czasami trudno jest połączyć.

Internet (LocationManager.NETWORK_PROVIDER) jest znacznie szybsze niż GPS, ale mniej dokładna niż GPS

Jeżeli nieosiągalny GPS i trzeba bieżącą lokalizację następnie LocationManager daje dostępnych danych, które są pobierane z Internetu . (W tym przypadku można również sprawdzić dostawcę lokalizacji).

Przepraszam za mój zły język angielski, czy to trudne do zrozumienia, prosimy o komentarz

8

miejsce, które można uzyskać z API będą musiały dokładność w metrów. Powinieneś również sprawdzić, ile lat ma ta lokalizacja.

https://developer.android.com/reference/android/location/Location.html#getAccuracy()

https://developer.android.com/reference/android/location/Location.html#getTime()

Ludzie zazwyczaj usunąć lokalizację, jeśli dokładność jest większa niż 50 lub 100m.


Dlaczego tak się dzieje?

GPS potrzebuje trochę czasu, aby znaleźć satelity i uzyskać sygnał. Ponadto interfejs API spróbuje określić Twoją lokalizację na podstawie Twojej sieci. Jest to rodzaj przeskoku między siecią a GPS, dopóki GPS nie dostarczy pewnych dokładnych danych.


Jak tego uniknąć?

W swoim detektorze lokalizacji sprawdź dokładność i poczekaj, aż uzyskasz lepszą dokładność.

+0

Używamy lokalizacji do rejestracji czasu z detektorem lokalizacji.Nasi użytkownicy nie zaakceptują czekania, więc nie odnotujemy niczego, jeśli dokładność jest zła. Mimo to Google czasami dostarcza lokalizacje, które mają OGROMNĄ różnicę (> 10 km) od rzeczywistości i określa je jako dokładne. Mamy pewne "teorie spiskowe" na temat przeniesionych routerów bezprzewodowej sieci LAN i tak dalej. Jeśli sam muszę sobie poradzić z dokładnością, rzeczy z Google nie mają żadnego sensu. –

2

Najlepszy sposób rozwiązania tego problemu, filtrowanie wyników. Prawdopodobieństwo poprawnej lokalizacji zwróconej z usługi Fuse wynosi 67%, co oznacza, że ​​możesz dostać niewłaściwą lokalizację w 1/3.

Powinieneś porównać poprzednią lokalizację (lub więcej niż jedną, aby mieć pewność, zachować je na liście) z bieżącą, zanim uzyskasz lokalizację. Jeśli istnieje zauważalna różnica, nie używaj najnowszej.

Uwaga: nie zapisuj lokalizacji użytkownika w pliku lub folderze, nie stosuj polityki prywatności, tylko porównaj z lastKnownLocation lub lokalizacjami odebranymi w bieżącej sesji.

Innym pomysłem jest, jeśli używasz GoogleApiClient, aktualnie używam, istnieje nowa klasa dla zfuzowanej lokalizacji FusedLocationProvider, możesz to sprawdzić.

Również w zakresie, w jakim zrozumiałem, ustawiają limit pobierania lokalizacji na godzinę dla urządzeń z Androidem 8.0 (poziom API 26) i późniejszych. Możesz sprawdzić this document dla nowego zachowania.

4

dla Google lokalizacji topionego API można użyć poniżej kod

package com.hydrometcloud.location; 

import android.app.Activity; 
import android.content.Context; 
import android.content.IntentSender; 
import android.location.Location; 
import android.os.Bundle; 
import android.support.annotation.NonNull; 
import android.support.annotation.Nullable; 
import android.util.Log; 

import com.google.android.gms.common.ConnectionResult; 
import com.google.android.gms.common.api.GoogleApiClient; 
import com.google.android.gms.common.api.PendingResult; 
import com.google.android.gms.common.api.ResultCallback; 
import com.google.android.gms.common.api.Status; 
import com.google.android.gms.location.LocationListener; 
import com.google.android.gms.location.LocationRequest; 
import com.google.android.gms.location.LocationServices; 
import com.google.android.gms.location.LocationSettingsRequest; 
import com.google.android.gms.location.LocationSettingsResult; 
import com.google.android.gms.location.LocationSettingsStatusCodes; 


public class GoogleLocation implements 
     GoogleApiClient.ConnectionCallbacks, 
     GoogleApiClient.OnConnectionFailedListener, 
     LocationListener, 
     ResultCallback<LocationSettingsResult> { 

    private LocationSettingsRequest mLocationSettingsRequest; 
    private GoogleApiClient mGoogleApiClient; 
    private LocationRequest mLocationRequest; 
    private String TAG = "GoogleLocation"; 

    private Context context; 
    private long UPDATE_INTERVAL = 10 * 1000; /* 10 secs */ 
    private long FASTEST_INTERVAL = 2000; /* 2 sec */ 
    private GoogleLocationCallback googleLocationCallback; 

    private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; 
    public static final int REQUEST_CHECK_SETTINGS = 0x1; 

    public GoogleLocation(Context context) { 
     this.context = context; 
     setUpLocation(); 
    } 

    public void setGoogleLocationCallback(GoogleLocationCallback googleLocationCallback) { 
     this.googleLocationCallback = googleLocationCallback; 
    } 

    private void setUpLocation() { 

     mGoogleApiClient = new GoogleApiClient.Builder(context.getApplicationContext()) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(LocationServices.API) 
       .build(); 

     // Create the LocationRequest object 
     mLocationRequest = LocationRequest.create() 
       .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) 
       .setInterval(UPDATE_INTERVAL)  // 10 seconds, in milliseconds 
       .setFastestInterval(FASTEST_INTERVAL); // 1 second, in milliseconds 

     locationEnable(); 
    } 

    public void googleClientConnect() { 
     mGoogleApiClient.connect(); 
    } 

    public void googleClientDisConnect() { 
     if (mGoogleApiClient.isConnected()) { 
      mGoogleApiClient.unregisterConnectionCallbacks(this); 
      mGoogleApiClient.unregisterConnectionFailedListener(this); 
      LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); 
      mGoogleApiClient.disconnect(); 
      mGoogleApiClient = null; 
     } 
    } 

    private void locationEnable() { 
     LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); 
     builder.addLocationRequest(mLocationRequest); 
     mLocationSettingsRequest = builder.build(); 
     checkLocationSettings(); 
    } 

    private void checkLocationSettings() { 
     PendingResult<LocationSettingsResult> result = 
       LocationServices.SettingsApi.checkLocationSettings(
         mGoogleApiClient, 
         mLocationSettingsRequest 
       ); 
     result.setResultCallback(this); 
    } 

    @Override 
    public void onConnected(@Nullable Bundle bundle) { 
     Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); 
     if (location == null) { 
      updateLocation(); 
     } else { 
      handleNewLocation(location); 
     } 
    } 

    private void handleNewLocation(Location location) { 

     double currentLatitude = location.getLatitude(); 
     double currentLongitude = location.getLongitude(); 

     Log.e(TAG, "---currentLatitude--" + currentLatitude); 
     Log.e(TAG, "---currentLongitude--" + currentLongitude); 

     if (googleLocationCallback != null) { 
      googleLocationCallback.updateLocationListner(currentLatitude, currentLongitude); 
     } 

    } 

    public void updateLocation() { 
     LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); 
    } 

    @Override 
    public void onConnectionSuspended(int i) { 

    } 

    @Override 
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { 
        /* 
     * 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((Activity) context, 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. 
      */ 
      Log.e(TAG, "Location services connection failed with code " + connectionResult.getErrorCode()); 
     } 
    } 

    @Override 
    public void onResult(@NonNull LocationSettingsResult locationSettingsResult) { 
     final Status status = locationSettingsResult.getStatus(); 
     switch (status.getStatusCode()) { 
      case LocationSettingsStatusCodes.SUCCESS: 
       Log.e(TAG, "All location settings are satisfied."); 
       break; 
      case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: 
       Log.e(TAG, "Location settings are not satisfied. Show the user a dialog to" + 
         "upgrade location settings "); 

       try { 
        // Show the dialog by calling startResolutionForResult(), and check the result 
        // in onActivityResult(). 
        status.startResolutionForResult((Activity) context, REQUEST_CHECK_SETTINGS); 
       } catch (IntentSender.SendIntentException e) { 
        Log.e(TAG, "PendingIntent unable to execute request."); 
       } 
       break; 
      case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: 
       Log.e(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog " + 
         "not created."); 
       break; 
     } 
    } 

    @Override 
    public void onLocationChanged(Location location) { 
     handleNewLocation(location); 
    } 

    public interface GoogleLocationCallback { 
     void updateLocationListner(double latitude, double longitude); 
    } 
} 

Teraz wdrożenia wywołanie zwrotne GoogleLocation.GoogleLocationCallback na których działalność lub fragmentu sprowadzona lokalizację, a potem wpisz poniżej kod, na których działalność lub fragmentu ty dostać lokalizacja

googleLocation = new GoogleLocation(this); 
googleLocation.setGoogleLocationCallback(this); 
+0

Poszukuję odpowiedzi z wiarygodnych i/lub oficjalnych źródeł. Twoja odpowiedź to zawiera, czy nie? –

+0

Użyłem google fused location api i za pomocą tego, że dostaję dokładną lokalizację, dlatego tutaj dałem moją niestandardową klasę lokalizacji google ... więc może być przydatne dla ciebie. –

2

oficjalna strona deweloper Android ma stronę poświęconą Location Strategies do udanych aplikacji na Androida. Możesz przeczytać więcej tam, więc bez wchodzenia w szczegóły, oficjalna dokumentacja podaje następującą informację:

Możesz spodziewać się, że najnowsza poprawka lokalizacji jest najdokładniejsza. Jednak ponieważ dokładność poprawki lokalizacji jest różna, najnowsza poprawka nie zawsze jest najlepsza. Należy uwzględnić logikę wyboru poprawek lokalizacji na podstawie kilku kryteriów. Kryteria różnią się także w zależności od przypadków użycia aplikacji i testów w terenie.

Oto kilka kroków, które można podjąć, aby zweryfikować dokładność poprawki Lokalizacja:

  • Sprawdź, czy lokalizacja pobierana jest znacznie nowsza niż poprzedniego oszacowania.
  • Sprawdź, czy dokładność określona przez lokalizację jest lepsza lub gorsza od poprzedniej.
  • Sprawdź, z którego dostawcy pochodzi nowa lokalizacja i ustal, czy ufasz jej więcej.

Można również zajrzeć do realizacji podstawowego Kalman Filter w swojej aplikacji do utrzymywania i aktualizacji oszacowania lokalizacji użytkownika. Powodzenia.

0

Można to wykorzystać:

package com.amolood.news.manager; 

/** 
* Created by nasnasa on 14/02/2017. 
*/ 

import android.app.AlertDialog; 
import android.app.Service; 
import android.content.Context; 
import android.content.DialogInterface; 
import android.content.Intent; 
import android.location.Location; 
import android.location.LocationListener; 
import android.location.LocationManager; 
import android.os.Bundle; 
import android.os.IBinder; 
import android.provider.Settings; 
import android.util.Log; 


/** 
* Created by nasnasa on 14/01/2017. 
*/ 

public class GPSTracker extends Service implements LocationListener { 

    private final Context mContext; 

    // flag for GPS status 
    boolean isGPSEnabled = false; 

    // flag for network status 
    boolean isNetworkEnabled = false; 

    // flag for GPS status 
    boolean canGetLocation = false; 

    Location location; // location 
    double latitude; // latitude 
    double longitude; // longitude 

    // The minimum distance to change Updates in meters 
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters 

    // The minimum time between updates in milliseconds 
    private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute 

    // Declaring a Location Manager 
    protected LocationManager locationManager; 

    public GPSTracker(Context context) { 
     this.mContext = context; 
     getLocation(); 
    } 

    public Location getLocation() { 
     try { 
      locationManager = (LocationManager) mContext 
        .getSystemService(LOCATION_SERVICE); 

      // getting GPS status 
      isGPSEnabled = locationManager 
        .isProviderEnabled(LocationManager.GPS_PROVIDER); 

      // getting network status 
      isNetworkEnabled = locationManager 
        .isProviderEnabled(LocationManager.NETWORK_PROVIDER); 

      if (!isGPSEnabled && !isNetworkEnabled) { 
       // no network provider is enabled 
      } else { 
       this.canGetLocation = true; 
       // First get location from Network Provider 
       if (isNetworkEnabled) { 
        locationManager.requestLocationUpdates(
          LocationManager.NETWORK_PROVIDER, 
          MIN_TIME_BW_UPDATES, 
          MIN_DISTANCE_CHANGE_FOR_UPDATES, this); 
        Log.d("Network", "Network"); 
        if (locationManager != null) { 
         location = locationManager 
           .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); 
         if (location != null) { 
          latitude = location.getLatitude(); 
          longitude = location.getLongitude(); 
         } 
        } 
       } 
       // if GPS Enabled get lat/long using GPS Services 
       if (isGPSEnabled) { 
        if (location == null) { 
         locationManager.requestLocationUpdates(
           LocationManager.GPS_PROVIDER, 
           MIN_TIME_BW_UPDATES, 
           MIN_DISTANCE_CHANGE_FOR_UPDATES, this); 
         Log.d("GPS Enabled", "GPS Enabled"); 
         if (locationManager != null) { 
          location = locationManager 
            .getLastKnownLocation(LocationManager.GPS_PROVIDER); 
          if (location != null) { 
           latitude = location.getLatitude(); 
           longitude = location.getLongitude(); 
          } 
         } 
        } 
       } 
      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return location; 
    } 

    /** 
    * Stop using GPS listener 
    * Calling this function will stop using GPS in your app 
    * */ 
    public void stopUsingGPS(){ 
     if(locationManager != null){ 
      locationManager.removeUpdates(GPSTracker.this); 
     } 
    } 

    /** 
    * Function to get latitude 
    * */ 
    public double getLatitude(){ 
     if(location != null){ 
      latitude = location.getLatitude(); 
     } 

     // return latitude 
     return latitude; 
    } 

    /** 
    * Function to get longitude 
    * */ 
    public double getLongitude(){ 
     if(location != null){ 
      longitude = location.getLongitude(); 
     } 

     // return longitude 
     return longitude; 
    } 

    /** 
    * Function to check GPS/wifi enabled 
    * @return boolean 
    * */ 
    public boolean canGetLocation() { 
     return this.canGetLocation; 
    } 

    /** 
    * Function to show settings alert dialog 
    * On pressing Settings button will lauch Settings Options 
    * */ 
    public void showSettingsAlert(){ 
     AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext); 

     // Setting Dialog Title 
     alertDialog.setTitle("GPS is settings"); 

     // Setting Dialog Message 
     alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?"); 

     // On pressing Settings button 
     alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() { 
      public void onClick(DialogInterface dialog,int which) { 
       Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); 
       mContext.startActivity(intent); 
      } 
     }); 

     // on pressing cancel button 
     alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 
      public void onClick(DialogInterface dialog, int which) { 
       dialog.cancel(); 
      } 
     }); 

     // Showing Alert Message 
     alertDialog.show(); 
    } 

    @Override 
    public void onLocationChanged(Location location) { 
    } 

    @Override 
    public void onProviderDisabled(String provider) { 
    } 

    @Override 
    public void onProviderEnabled(String provider) { 
    } 

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

    @Override 
    public IBinder onBind(Intent arg0) { 
     return null; 
    } 

} 

takie jak ta na swojej działalności

GPSTracker gps = new GPSTracker(this); 

gps.getlocation(); 
double latitude = gps.getLatitude(); 
double longitude = gps.getLongitude(); 
Powiązane problemy