LocationManager和跳跃坐标

时间:2017-12-27 11:47:02

标签: java android google-maps locationmanager

看看这张图片。你会看到一些LocationManager如何给出奇怪的坐标。看起来他们跳了起来。但同时原生谷歌地图应用程序显示移动设备的正确位置。

我在Android 7.0.0和7.1.1下使用3种不同的智能手机测试了应用程序,并且或多或少得到了相同的结果。

请帮我查看我的代码,看看它还缺少哪些设置。

谢谢!

enter image description here

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.text.format.DateFormat;
import android.util.Log;
import com.google.gson.Gson;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.Date;

public class gps_service2 extends Service {
    private static final String TAG = "GPS SERVICE";
    private LocationManager mLocationManager = null;
    private static final int LOCATION_INTERVAL = 15000;
    private static final float LOCATION_DISTANCE = 10f;
    Context context;

    private class LocationListener implements android.location.LocationListener
    {
        Location mLastLocation;

        public LocationListener(String provider)
        {
            Log.e(TAG, "LocationListener " + provider);
            mLastLocation = new Location(provider);
        }

        @Override
        public void onLocationChanged(Location location)
        {
            Log.e(TAG, "onLocationChanged: " + location);

            try
            {
                ComplexPreferences complexPreferences = ComplexPreferences.getComplexPreferences(context, "App_Settings", 0);
                AppSettings appSettings = complexPreferences.getObject("App_Settings", AppSettings.class);

                boolean isMobileDataEnabled = Utils.isMobileDataEnabled(context);

                if (appSettings != null && (isMobileDataEnabled)) {

                    LocationItem locationItem = new LocationItem();
                    locationItem.DeviceID = appSettings.getDeviceID();
                    locationItem.Latitude =  Double.toString(location.getLatitude());
                    locationItem.Longitude = Double.toString(location.getLongitude());
                    Date d = new Date();
                    CharSequence timeOfRequest = DateFormat.format("yyyy-MM-dd HH:mm:ss", d.getTime());  
                    locationItem.TimeOfRequest = timeOfRequest.toString();
                    locationItem.SerialNumber = appSettings.getSerialNumber();

                    mLastLocation.set(location);

                    Gson gson = new Gson();
                    String requestObject = gson.toJson(locationItem);
                    Log.d(TAG, "Формирование URL API сервера");
                    String url = appSettings.getIpAddress() + "/api/staff/savedata";
                    makeRequest(url, requestObject, dLocation);
                }
            }
            catch (Exception ex)
            {
                Log.d(TAG, "Ошибка: " + ex.getMessage());
            }
        }

        @Override
        public void onProviderDisabled(String provider)
        {
            Log.e(TAG, "onProviderDisabled: " + provider);
        }

        @Override
        public void onProviderEnabled(String provider)
        {
            Log.e(TAG, "onProviderEnabled: " + provider);
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras)
        {
            Log.e(TAG, "onStatusChanged: " + provider);
        }
    }

    LocationListener[] mLocationListeners = new LocationListener[] {
            new LocationListener(LocationManager.GPS_PROVIDER),
            new LocationListener(LocationManager.NETWORK_PROVIDER)
    };

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        Log.e(TAG, "onStartCommand");
        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

    @Override
    public void onCreate()
    {
        context = this;
        Log.e(TAG, "onCreate");
        initializeLocationManager();
        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
                    mLocationListeners[1]);
        } catch (java.lang.SecurityException ex) {
            Log.i(TAG, "fail to request location update, ignore", ex);
        } catch (IllegalArgumentException ex) {
            Log.d(TAG, "network provider does not exist, " + ex.getMessage());
        }
        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
                    mLocationListeners[0]);
        } catch (java.lang.SecurityException ex) {
            Log.i(TAG, "fail to request location update, ignore", ex);
        } catch (IllegalArgumentException ex) {
            Log.d(TAG, "gps provider does not exist " + ex.getMessage());
        }
    }

    @Override
    public void onDestroy()
    {
        Log.e(TAG, "onDestroy");
        super.onDestroy();
        if (mLocationManager != null) {
            for (int i = 0; i < mLocationListeners.length; i++) {
                try {
                    mLocationManager.removeUpdates(mLocationListeners[i]);
                } catch (Exception ex) {
                    Log.i(TAG, "fail to remove location listners, ignore", ex);
                }
            }
        }
    }

    private void initializeLocationManager() {
        Log.e(TAG, "initializeLocationManager");
        if (mLocationManager == null) {
            mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        }
    }

    public static double round(double value, int places) {
        if (places < 0) throw new IllegalArgumentException();
        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(places, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }

    public void makeRequest(String uri, String json, DLocation dLocation) {
        HandlerThread handlerThread = new HandlerThread("URLConnection");
        handlerThread.start();
        Handler mainHandler = new Handler(handlerThread.getLooper());
        Runnable myRunnable = createRunnable(uri, json, dLocation);
        mainHandler.post(myRunnable);
    }

    private Runnable createRunnable(final String uri, final String data,final DLocation dLocation){

        Runnable aRunnable = new Runnable(){
            public void run(){
                try {   
                    //Connect
                    HttpURLConnection urlConnection;
                    urlConnection = (HttpURLConnection) ((new URL(uri).openConnection()));
                    urlConnection.setDoOutput(true);
                    urlConnection.setRequestProperty("Content-Type", "application/json");
                    urlConnection.setRequestProperty("Accept", "application/json");
                    urlConnection.setRequestMethod("POST");

                    urlConnection.setConnectTimeout(12000);
                    urlConnection.setReadTimeout(10000); 

                    urlConnection.connect();

                    //Write
                    OutputStream outputStream = urlConnection.getOutputStream();
                    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
                    try {
                        writer.write(data);
                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.d(TAG,"Ошибка записи в буфер для пережачи по HTTP");
                    }
                    writer.close();
                    outputStream.close();

                    //Read
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));

                    String line = null;
                    StringBuilder sb = new StringBuilder();

                    while ((line = bufferedReader.readLine()) != null) {
                        sb.append(line);
                    }

                    bufferedReader.close();
                    String result = sb.toString();

                    Log.d(TAG, result);                    

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

                    Log.d(TAG, "Ошибка HTTP " + e.getMessage());
                }
                catch( Exception e){
                    e.printStackTrace();
                }
            }
        };

        return aRunnable;

    }

}

1 个答案:

答案 0 :(得分:3)

这是智能手机/消费级GPS的典型行为。要减少波动,您需要将结果标准化。一种方法是从坐标队列计算地理中心,例如:https://github.com/Esri/cordova-plugin-advanced-geolocation/blob/master/src/com/esri/cordova/geolocation/utils/GeodataHelper.java#L56

public class Coordinate {
    public double latitude;
    public double longitude;
    public float accuracy;
}

public static Coordinate getGeographicCenter(final ConcurrentLinkedQueue<Coordinate> queue){
    double x = 0;
    double y = 0;
    double z = 0;
    float accuracy = 0;
    int radiusKM = 6367;

    for(final Coordinate coordinate : queue){
        accuracy += coordinate.accuracy;

        // Convert latitude and longitude to radians
        final double latRad = Math.PI * coordinate.latitude / 180;
        final double lonRad = Math.PI * coordinate.longitude / 180;

        // Convert to cartesian coords
        x += radiusKM * Math.cos(latRad) * Math.cos(lonRad);
        y += radiusKM * Math.cos(latRad) * Math.sin(lonRad);
        z += radiusKM * Math.sin(latRad);
    }

    // Get our averages
    final double xAvg = x / queue.size();
    final double yAvg = y / queue.size();
    final double zAvg = z / queue.size();
    final float accuracyAvg = accuracy / queue.size();

    // Convert cartesian back to radians
    final double sphericalLatRads = Math.asin(zAvg / radiusKM);
    final double sphericalLonRads = Math.atan2(yAvg, xAvg);

    // Convert radians back to latitude and longitude
    Coordinate centerPoint = new Coordinate();
    centerPoint.latitude = sphericalLatRads * (180 / Math.PI);
    centerPoint.longitude = sphericalLonRads * (180 / Math.PI);
    centerPoint.accuracy = accuracyAvg;

    return centerPoint;
}