Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
287 views
in Technique[技术] by (71.8m points)

java - LocationManager and jumping coordinates

Take a look at this image. You see that some how LocationManager gives weird coordinates. It looks like they jump. But at the same time native google map app display correct location of the moving device.

I tested app with 3 different smartphones under Android 7.0.0 and 7.1.1 and get the same result more or less.

Please help me check my code to see which settings it is missing still.

Thank you!

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;

    }

}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

That's pretty typical behavior from a smartphone/consumer-grade GPS. To reduce the fluctuations you'll need to normalize the results. One approach is to compute the geographic center from a queue of coordinates, for example: 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;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...