问题描述
我们有一个应用程序,可以使用Google Play服务位置API捕获用户的位置,用于Geotag land等每笔交易,下订单等。
从移动设备捕获这些位置后,我们会将其同步到服务器并在Web仪表板中显示。
我们注意到在少数情况下,在几秒钟内捕获的交易具有不同距离的位置结果。
示例 :
用户的位置将在
Mandsaur,Madhya Pradesh,印度,亚洲
(纬度 - 24.057291,经度 - 75.0970672,捕获日期 - 2017-01-04 09:19:48 )。
但随后的交易将有位置
巴黎距离酒店6772公里
(纬度 - 48.8581074,经度 - 2.3525187,捕获日期 - 2017-01-04 09:20:01 )
有时取指令错误陈述的像印度用户从古吉拉特然后位置比哈尔邦,马哈拉施特拉邦,科威特的获取(从印度)它真的头疼印度开发商
因为这发生在没有用户干扰且用户设备中没有安装模拟位置应用程序的情况下。
任何人都可以解释为什么会这样,我们怎么能避免这些情况?
注意:
这些交易位置通常在打开GPS的情况下捕获,并设置为高精度模式
1楼
您从API获得的位置将具有以米为单位的精度 。 您还应该检查位置的年龄。
如果准确度大于50或100米,人们通常会丢弃该位置。
为什么会这样?
设备的GPS需要一些时间才能找到卫星并获得信号。 此外,API会尝试根据您的网络确定您的位置。 它是网络和GPS之间的各种跳跃,直到GPS提供一些准确的数据。
怎么避免这个?
在您的位置监听器中,检查准确性并等到准确性更高。
2楼
对于谷歌位置融合api,您可以使用下面的代码
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);
}
}
现在,您实现回调GoogleLocation.GoogleLocationCallback,在其中获取位置的活动或片段,然后在下面写下您获取位置的活动或片段的代码
googleLocation = new GoogleLocation(this);
googleLocation.setGoogleLocationCallback(this);
3楼
官方Android开发者网站有一个专门针对成功Android应用的的页面。 你可以在那里阅读更多,所以没有详细说明,官方文档说明以下内容......
您可能希望最新的位置修复最准确。 但是,由于定位的准确性不同,最近的修复并不总是最好的。 您应该包含基于多个条件选择位置修复的逻辑。 标准也根据应用和现场测试的使用情况而有所不同。
您可以采取以下几个步骤来验证位置修复的准确性:
- 检查检索到的位置是否明显高于先前的估计值。
- 检查该位置声明的准确度是否优于或低于先前的估计值。
- 检查新位置来自哪个提供商,并确定您是否更信任它。
您可能还希望在应用程序中实现基本 ,以维护和更新用户位置的估计值。 祝好运。
4楼
解决此问题的最佳方法是过滤结果。 从Fuse服务返回的正确位置的概率为67%,这意味着您可以在1/3中找到错误的位置。
在获取位置之前,您应该将之前的位置(或多个,以确保它们保留在列表中)与当前位置进行比较。 如果存在明显差异,请勿使用最新版本。
注意:不要将用户位置保存到文件或文件夹,这是违反隐私策略的,只是与lastKnownLocation或当前会话中收到的位置进行比较。
另一个想法是,如果你正在使用GoogleApiClient
,我目前正在使用,有一个新的融合位置类,你可以检查出来。
此外,据我所知,他们为Android 8.0(API级别26)及更高版本的设备每小时提供4个位置检索限制。 您可以查看以了解新行为。
5楼
我在印度普纳遇到了同样的问题。 用于测试的设备是Swipe平板电脑,
解决方案 :我保留最后的纬度和经度并更新时间 ,当下一个纬度和经度更新时,计算这两个位置之间的距离,如果距离高于100公里 ,则不计算。
我用来计算距离的方法
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);
}
为什么会这样
在Android设备上有2个选项来获取位置
- 全球定位系统
- 互联网
GPS (LocationManager.GPS_PROVIDER):与互联网相比较慢,但它比互联网准确,在偏远地区GPS连接速度较慢,有时难以连接。
Internet (LocationManager.NETWORK_PROVIDER):比GPS快得多,但它不如GPS准确
如果GPS无法访问且您需要当前位置,则LocationManager将为您提供可从互联网获取的可用数据。 (在这种情况下,您还可以检查位置提供商。)
6楼
你可以用这个:
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;
}
}
就像你的活动一样
GPSTracker gps = new GPSTracker(this);
gps.getlocation();
double latitude = gps.getLatitude();
double longitude = gps.getLongitude();