Android onLocationChanged не соблюдает минимальную продолжительность обновления и обновляет более старую, чем предыдущая - PullRequest
1 голос
/ 22 февраля 2020

Я наблюдаю странное поведение, наблюдая за временем обновления местоположений с помощью GPS LocationListener.

Иногда (хотя и с перерывами) я вижу, что у обновленного местоположения есть временная метка за доли секунды (несмотря на то, что минимальное обновление устанавливается равным 5000 миллисекундам в requestUpdates) или иногда даже раньше , чем предыдущее местоположение?

Пример обоих, рассматриваемых как доли секунды перед предыдущим местоположением (вывод logcat, отредактированный для ясности) :

GpsTracker_v4: onLocationChanged: Warning: location update is older than previous location
D/GpsTracker_v4: 
    previous location:
        provider: network
        time:20/02/22 06:07:17.468
    ---
    new location:
        provider: network
        time: 20/02/22 06:07:17.467

Я уже достаточно зарегистрировался, чтобы (справедливо) уверенно утверждать, что это не из-за конфликта gps / сетевого провайдера или из-за того, что он разнесен только на миллисекунды (например, более длительный период до секунд) долго включается внизу поста)

Весь мой класс трекера (за исключением десятков журналов отладки):

public class GpsTracker_v4 {
    /*--------------------------------------
        CONSTANTS
    --------------------------------------*/
    private static final String TAG = GpsTracker_v4.class.getSimpleName();

    // location updates interval - 5sec
    private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 5000;


    /*--------------------------------------
        MEMBER VARIABLES
    --------------------------------------*/
    //---VARIABLES---
    Context context;
    LocationManager locationManager;
    LocationListener locationListener;

    Location previousLocation = null;


    /*--------------------------------------
        CONSTRUCTOR
    --------------------------------------*/
    //-create manager and initialise location listener
    public GpsTracker_v4(Context c) {
        this.context = c;

        locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

        locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {

                if (location != null) {
                    if (previousLocation != null) {

                        //check location update is more recent than previous
                        if (checkUpdateTime(location)) {
                            Log.d(TAG, "onLocationChanged: new location more recent");
                        } else {
                            Log.w(TAG, "onLocationChanged: Warning: location update is " +
                                    "older than previous location");
                        }

                        Log.d(TAG, "previous location:\n" +
                                "provider: " + previousLocation.getProvider() + "\n" +
                                "time:" + getDateString(previousLocation.getTime()) + "\n" +
                                "---\n" +
                                "new location:\n" +
                                "provider: " + location.getProvider() + "\n" +
                                "time: " + getDateString(location.getTime()));

                        //check location is more accurate than previous location
                        if (checkUpdateAccuracy(location)) {
                            Log.d(TAG, "onLocationChanged: location update is more accurate");
                        } else {
                            Log.w(TAG, "onLocationChanged: Warning: location update is " +
                                    "less accurate or equal to previous");
                        }

                        Log.d(TAG, "Prev location:\n" +
                                "provider: " + previousLocation.getProvider() + "\n" +
                                "accuracy: " + previousLocation.getAccuracy() + "\n" +
                                "---\n" +
                                "New location:\n" +
                                "provider: " + location.getProvider() + "\n" +
                                "accuracy: " + location.getAccuracy());
                    } else {
                        //no previous location yet
                        Log.d(TAG, "onLocationChanged: previousLocation is null: " +
                                "using first location update:");
                    }

                    //replace previous location with updated
                    previousLocation = location;
                    //debugging attempt: remove all content of location 
                    location = null;
                } else {
                    //null location passed
                    Log.e(TAG, "onLocationChanged: Error: passed location is NULL");
                    //todo: handle
                }
            }

            @Override
            public void onStatusChanged(String s, int i, Bundle bundle) {
                //todo:
            }

            @Override
            public void onProviderEnabled(String s) {
                //todo:
            }

            @Override
            public void onProviderDisabled(String s) {
                //todo:
            }
        };

        beginRequestUpdates();
    }


    /*--------------------------------------
        METHODS
    --------------------------------------*/
    //-begin requesting updates from both gps and network providers
    public void beginRequestUpdates() {
        //permission check (IDE insists its done here, not earlier or in another method)
        if (ContextCompat.checkSelfPermission(context,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(
                context, Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            Log.e(TAG, "checkPermission: Error: Permission not been granted.);
            return;
        }

        //begin GPs updates
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                UPDATE_INTERVAL_IN_MILLISECONDS,
                0,
                locationListener,
                Looper.getMainLooper());
        Log.d(TAG, "beginRequestUpdates: GPS updates requested");

        //begin network updates
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                UPDATE_INTERVAL_IN_MILLISECONDS,
                0,
                locationListener,
                Looper.getMainLooper());
        Log.d(TAG, "beginRequestUpdates: Network updates requested");
    }


    /*--------------------------------------
        HELPER METHODS
    --------------------------------------*/
    //-return true if time of location update is more recent than previous update time
    public boolean checkUpdateTime(Location location) {
        return location.getTime() > previousLocation.getTime();
    }


    //-return true if location update is more accurate than previous location
    public boolean checkUpdateAccuracy(Location location) {
        return location.getAccuracy() < previousLocation.getAccuracy();
    }


    //-get user-readable date/time from milli (in year-month-day format)
    private String getDateString(long milliSeconds) {
        String dateFormat = "yy/MM/dd hh:mm:ss.SSS";
        SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(milliSeconds);
        return formatter.format(calendar.getTime());
    }


    public void printLocation(Location location) {
        System.out.println("" +
                "Provider: " + location.getProvider() + "\n" +
                "Latitude: " + location.getLatitude() + "\n" +
                "Longitude: " + location.getLongitude() + "\n" +
                "Accuracy: " + location.getAccuracy() + "\n" +
                "Time: " + getDateString(location.getTime()) + "\n");
    }


    /*--------------------------------------
        MUTATORS
    --------------------------------------*/
    //-set listener from outside class
    public void setListener(LocationListener listener) {
        this.locationListener = listener;
    }
}

В чем причина такого поведения?

Редактировать

Вот лучший пример того, как обновление местоположения обновляется до предыдущей отметки:

updated location:
    Time: 20/02/22 06:44:57.346
previous location:
    Time: 20/02/22 06:45:21.370
...