2017-12-27 262 views
0

看看這個圖像。你會看到一些LocationManager如何給出奇怪的座標。看起來他們跳起來了。但與此同時,本地谷歌地圖應用程序顯示移動設備的正確位置。LocationManager和跳躍座標

我使用3款不同的智能手機在Android 7.0.0和7.1.1下測試了應用程序,並獲得了相同的結果。

請幫我檢查我的代碼,看看它仍然丟失了哪些設置。

謝謝!

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

,從智能手機/消費級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; 
} 
+1

請添加一些代碼片段來說明如何「正常化的結果」。鏈接將來可能會被打破。 – 0X0nosugar

+0

嗨!安迪!非常感謝你的評論!請介意給我們建議多少座標,以及我們必須使用建議的功能?假設我們每分鐘得到6分,並計算每分鐘的最佳位置是否可以? –

+0

即使設備沒有移動,活動的GPS通常每分鐘發送的路數也會超過6次。嘗試從10個座標開始並進行實驗以獲得您想要的結果。較小的隊列大小對於應用程序性能更好。我還建議在測試時使用Android Studio工具來關注CPU,內存使用情況和垃圾回收。強大的GPS使用和使用當前一代芯片組的標準化程序對電池壽命和用戶體驗可能非常困難。 –